<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Destiny Obs</title>
    <description>The latest articles on DEV Community by Destiny Obs (@destinyobs).</description>
    <link>https://dev.to/destinyobs</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%2F1974798%2F8ee24a59-8d03-48c1-8f82-de7d76656e96.png</url>
      <title>DEV Community: Destiny Obs</title>
      <link>https://dev.to/destinyobs</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/destinyobs"/>
    <language>en</language>
    <item>
      <title>The Complete Beginner's Guide to vpcctl: Building Virtual Networks on Linux</title>
      <dc:creator>Destiny Obs</dc:creator>
      <pubDate>Tue, 11 Nov 2025 08:20:11 +0000</pubDate>
      <link>https://dev.to/destinyobs/the-complete-beginners-guide-to-vpcctl-building-virtual-networks-on-linux-36le</link>
      <guid>https://dev.to/destinyobs/the-complete-beginners-guide-to-vpcctl-building-virtual-networks-on-linux-36le</guid>
      <description>&lt;p&gt;&lt;strong&gt;A hands-on, beginner-friendly guide to understanding Virtual Private Clouds and building isolated networks on a single Linux machine&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Introduction: What Problem Are We Solving?&lt;/li&gt;
&lt;li&gt;
Understanding the Basics

&lt;ul&gt;
&lt;li&gt;What is a VPC?&lt;/li&gt;
&lt;li&gt;What is a Subnet?&lt;/li&gt;
&lt;li&gt;What is NAT?&lt;/li&gt;
&lt;li&gt;What is Peering?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Real-World Scenario: The Coffee Shop Network&lt;/li&gt;
&lt;li&gt;How vpcctl Works Under the Hood&lt;/li&gt;
&lt;li&gt;Prerequisites and Installation&lt;/li&gt;
&lt;li&gt;Quick Start: Your First VPC&lt;/li&gt;
&lt;li&gt;Deep Dive: Understanding Each Command&lt;/li&gt;
&lt;li&gt;Architecture Overview&lt;/li&gt;
&lt;li&gt;Command Reference&lt;/li&gt;
&lt;li&gt;Advanced Scenarios&lt;/li&gt;
&lt;li&gt;Troubleshooting Common Issues&lt;/li&gt;
&lt;li&gt;Complete Code Reference&lt;/li&gt;
&lt;li&gt;Best Practices&lt;/li&gt;
&lt;li&gt;Learning Resources&lt;/li&gt;
&lt;li&gt;Credits&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Introduction: What Problem Are We Solving?
&lt;/h2&gt;

&lt;p&gt;Imagine you're a developer working on a web application with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A web server that customers access&lt;/li&gt;
&lt;li&gt;A database that stores customer data&lt;/li&gt;
&lt;li&gt;An admin panel for internal staff&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You want to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Isolate your database so random people on the internet can't access it&lt;/li&gt;
&lt;li&gt;Allow your web server to talk to the database&lt;/li&gt;
&lt;li&gt;Control which ports and services are accessible from outside&lt;/li&gt;
&lt;li&gt;Test everything locally before deploying to the cloud&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Cloud providers (AWS, Azure, Google Cloud) solve this with VPCs (Virtual Private Clouds). vpcctl lets you simulate VPCs locally on Linux using native networking features.&lt;/p&gt;




&lt;h2&gt;
  
  
  Understanding the Basics
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is a VPC?
&lt;/h3&gt;

&lt;p&gt;VPC stands for Virtual Private Cloud. It's a logically isolated network where you control IP ranges, routing, internet access, and security rules. Think of it like an office building where you control entrances, floors, and WiFi.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is a Subnet?
&lt;/h3&gt;

&lt;p&gt;A subnet is a smaller network inside your VPC with its own IP range and purpose (e.g., public web, private database). Common types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Public subnet: can reach the internet and may accept inbound traffic&lt;/li&gt;
&lt;li&gt;Private subnet: no direct internet access; used for internal services&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What is NAT?
&lt;/h3&gt;

&lt;p&gt;NAT (Network Address Translation) lets private subnets access the internet without exposing them. Like a hotel reception calling restaurants on behalf of guests—responses come back via reception.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is Peering?
&lt;/h3&gt;

&lt;p&gt;Peering connects two VPCs so they can talk privately. Useful for connecting apps across isolated networks while allowing only specific subnets to communicate.&lt;/p&gt;




&lt;h2&gt;
  
  
  Real-World Scenario: The Coffee Shop Network
&lt;/h2&gt;

&lt;p&gt;Picture a coffee shop:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Customer Area = Public subnet (internet access, open to customers)&lt;/li&gt;
&lt;li&gt;Kitchen = Private subnet (staff-only, no direct internet from outside)&lt;/li&gt;
&lt;li&gt;Office = Another private subnet (admin-only)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Translating to vpcctl, creating a VPC is like building that coffee shop; adding subnets creates the areas; NAT is the WiFi router; firewall rules control who gets in.&lt;/p&gt;




&lt;h2&gt;
  
  
  How vpcctl Works Under the Hood
&lt;/h2&gt;

&lt;p&gt;vpcctl uses Linux primitives:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Network namespaces: isolated network environments per subnet&lt;/li&gt;
&lt;li&gt;veth pairs: virtual cables connecting namespaces to the VPC&lt;/li&gt;
&lt;li&gt;Linux bridges: the VPC switch interconnecting subnets&lt;/li&gt;
&lt;li&gt;iptables: firewall rules, NAT, and peering enforcement&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Prerequisites and Installation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  System Requirements
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Linux (Ubuntu 20.04+/Debian 10+ recommended). Use WSL/VM on Windows if needed.&lt;/li&gt;
&lt;li&gt;Root access (sudo) required&lt;/li&gt;
&lt;li&gt;Tools: Python 3.6+, iproute2 (ip), iptables, curl, tcpdump, bridge-utils&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Install Steps
&lt;/h3&gt;

&lt;p&gt;1) Install required packages&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; python3 iproute2 iptables curl tcpdump bridge-utils
&lt;span class="c"&gt;# CentOS/RHEL: sudo yum install -y python3 iproute iptables curl tcpdump bridge-utils&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2) Get vpcctl&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/DestinyObs/HNGi13-Stage4-vpcctl
&lt;span class="nb"&gt;cd &lt;/span&gt;HNGi13-Stage4-vpcctl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;3) Make it available as a command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x vpcctl.py
&lt;span class="nb"&gt;sudo ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/vpcctl.py"&lt;/span&gt; /usr/local/bin/vpcctl
vpcctl &lt;span class="nt"&gt;--help&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl flag-check  &lt;span class="c"&gt;# safe: validates parser only&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Quick Start: Your First VPC
&lt;/h2&gt;

&lt;p&gt;We'll use these consistent names and CIDRs everywhere:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;myvpc: 10.10.0.0/16

&lt;ul&gt;
&lt;li&gt;public: 10.10.1.0/24&lt;/li&gt;
&lt;li&gt;private: 10.10.2.0/24&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;othervpc: 10.20.0.0/16

&lt;ul&gt;
&lt;li&gt;public: 10.20.1.0/24&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 0: One-Time Checks
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl &lt;span class="nt"&gt;--help&lt;/span&gt; | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 5
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl flag-check
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 1: Create the VPC
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl create myvpc &lt;span class="nt"&gt;--cidr&lt;/span&gt; 10.10.0.0/16
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Add Subnets
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl add-subnet myvpc public  &lt;span class="nt"&gt;--cidr&lt;/span&gt; 10.10.1.0/24
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl add-subnet myvpc private &lt;span class="nt"&gt;--cidr&lt;/span&gt; 10.10.2.0/24
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Deploy Test Apps
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl deploy-app myvpc public  &lt;span class="nt"&gt;--port&lt;/span&gt; 8080
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl deploy-app myvpc private &lt;span class="nt"&gt;--port&lt;/span&gt; 8081
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Enable NAT (Internet Access for public)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;IFACE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;ip route get 1.1.1.1 | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'{print $5; exit}'&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;"Using host interface: &lt;/span&gt;&lt;span class="nv"&gt;$IFACE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl enable-nat myvpc &lt;span class="nt"&gt;--interface&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$IFACE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 5: Test Connectivity
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Private -&amp;gt; Public (intra-VPC)&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip netns &lt;span class="nb"&gt;exec &lt;/span&gt;ns-myvpc-private curl &lt;span class="nt"&gt;-s&lt;/span&gt; http://10.10.1.2:8080 | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 1

&lt;span class="c"&gt;# Public -&amp;gt; Internet (NAT)&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip netns &lt;span class="nb"&gt;exec &lt;/span&gt;ns-myvpc-public curl &lt;span class="nt"&gt;-I&lt;/span&gt; http://1.1.1.1 | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-5&lt;/span&gt; 

&lt;span class="c"&gt;# Host -&amp;gt; Private (should fail)&lt;/span&gt;
curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;--connect-timeout&lt;/span&gt; 2 http://10.10.2.2:8081 &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"private not reachable from host (expected)"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 6: Show VPC Isolation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl create othervpc &lt;span class="nt"&gt;--cidr&lt;/span&gt; 10.20.0.0/16
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl add-subnet othervpc public &lt;span class="nt"&gt;--cidr&lt;/span&gt; 10.20.1.0/24
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl deploy-app othervpc public &lt;span class="nt"&gt;--port&lt;/span&gt; 8080
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip netns &lt;span class="nb"&gt;exec &lt;/span&gt;ns-myvpc-public curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;--connect-timeout&lt;/span&gt; 2 http://10.20.1.2:8080 &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"blocked by default (expected)"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 7: Peer VPCs (Allow Only Public↔Public)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl peer myvpc othervpc &lt;span class="nt"&gt;--allow-cidrs&lt;/span&gt; 10.10.1.0/24,10.20.1.0/24
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip netns &lt;span class="nb"&gt;exec &lt;/span&gt;ns-myvpc-public curl &lt;span class="nt"&gt;-s&lt;/span&gt; http://10.20.1.2:8080 | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 8: Apply Security Policy
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl apply-policy myvpc policy_examples/example_ingress_egress_policy.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 9: Inspect and List
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl list
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl inspect myvpc | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 30
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 10: Cleanup
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl delete othervpc
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl delete myvpc
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Deep Dive: Understanding Each Command
&lt;/h2&gt;

&lt;p&gt;Below are the key commands and what happens under the hood.&lt;/p&gt;

&lt;h3&gt;
  
  
  create
&lt;/h3&gt;

&lt;p&gt;Command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl create myvpc &lt;span class="nt"&gt;--cidr&lt;/span&gt; 10.10.0.0/16
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What happens&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creates a Linux bridge br-myvpc and assigns 10.10.0.1/16&lt;/li&gt;
&lt;li&gt;Enables routing and prepares an iptables chain vpc-myvpc&lt;/li&gt;
&lt;li&gt;Records metadata to .vpcctl_data/vpc_myvpc.json&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Under the hood&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creates a Linux bridge device (br-myvpc) and brings it up&lt;/li&gt;
&lt;li&gt;Assigns the VPC gateway IP to the bridge interface and enables IPv4 forwarding (sysctl)&lt;/li&gt;
&lt;li&gt;Creates/uses a dedicated host iptables chain (vpc-myvpc) to keep VPC rules isolated and easy to clean up&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example 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="c"&gt;# Create bridge for the VPC and assign gateway IP&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip &lt;span class="nb"&gt;link &lt;/span&gt;add name br-myvpc &lt;span class="nb"&gt;type &lt;/span&gt;bridge
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip addr add 10.10.0.1/16 dev br-myvpc
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip &lt;span class="nb"&gt;link set &lt;/span&gt;br-myvpc up

&lt;span class="c"&gt;# Enable kernel forwarding&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;sysctl &lt;span class="nt"&gt;-w&lt;/span&gt; net.ipv4.ip_forward&lt;span class="o"&gt;=&lt;/span&gt;1

&lt;span class="c"&gt;# Create isolated chain for VPC rules and hook into FORWARD&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;iptables &lt;span class="nt"&gt;-N&lt;/span&gt; vpc-myvpc 2&amp;gt;/dev/null &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true
sudo &lt;/span&gt;iptables &lt;span class="nt"&gt;-C&lt;/span&gt; FORWARD &lt;span class="nt"&gt;-j&lt;/span&gt; vpc-myvpc 2&amp;gt;/dev/null &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;iptables &lt;span class="nt"&gt;-A&lt;/span&gt; FORWARD &lt;span class="nt"&gt;-j&lt;/span&gt; vpc-myvpc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  add-subnet
&lt;/h3&gt;

&lt;p&gt;Command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl add-subnet myvpc public &lt;span class="nt"&gt;--cidr&lt;/span&gt; 10.10.1.0/24
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What happens&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creates namespace ns-myvpc-public&lt;/li&gt;
&lt;li&gt;Creates a veth pair; one end attaches to br-myvpc, the other goes into the namespace&lt;/li&gt;
&lt;li&gt;Assigns 10.10.1.1/24 to the bridge and 10.10.1.2/24 inside the namespace; sets default route via 10.10.1.1&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Under the hood&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Adds a network namespace (ns-myvpc-public) and a veth pair (host end on br-myvpc, peer moved into the namespace)&lt;/li&gt;
&lt;li&gt;Configures IP addresses on both ends and sets the subnet's default route to the VPC bridge gateway&lt;/li&gt;
&lt;li&gt;Ensures interfaces are up and connected via the bridge for L2 switching between subnets in the same VPC&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example commands (public subnet 10.10.1.0/24)&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;# Create namespace and veth pair&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip netns add ns-myvpc-public
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip &lt;span class="nb"&gt;link &lt;/span&gt;add v-myvpc-public &lt;span class="nb"&gt;type &lt;/span&gt;veth peer name v-myvpc-public-ns

&lt;span class="c"&gt;# Attach host end to the VPC bridge&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip &lt;span class="nb"&gt;link set &lt;/span&gt;v-myvpc-public master br-myvpc
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip &lt;span class="nb"&gt;link set &lt;/span&gt;v-myvpc-public up

&lt;span class="c"&gt;# Move peer into the namespace and configure IPs&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip &lt;span class="nb"&gt;link set &lt;/span&gt;v-myvpc-public-ns netns ns-myvpc-public
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip addr add 10.10.1.1/24 dev br-myvpc
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip netns &lt;span class="nb"&gt;exec &lt;/span&gt;ns-myvpc-public ip addr add 10.10.1.2/24 dev v-myvpc-public-ns
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip netns &lt;span class="nb"&gt;exec &lt;/span&gt;ns-myvpc-public ip &lt;span class="nb"&gt;link set &lt;/span&gt;lo up
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip netns &lt;span class="nb"&gt;exec &lt;/span&gt;ns-myvpc-public ip &lt;span class="nb"&gt;link set &lt;/span&gt;v-myvpc-public-ns up
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip netns &lt;span class="nb"&gt;exec &lt;/span&gt;ns-myvpc-public ip route add default via 10.10.1.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  deploy-app
&lt;/h3&gt;

&lt;p&gt;Command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl deploy-app myvpc public &lt;span class="nt"&gt;--port&lt;/span&gt; 8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What happens&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Runs python3 -m http.server PORT in the target namespace&lt;/li&gt;
&lt;li&gt;Captures PID and stores it in metadata for reliable stop/cleanup&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Under the hood&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Executes the HTTP server with ip netns exec so the process is fully inside the subnet namespace&lt;/li&gt;
&lt;li&gt;Starts the server in the background and records its PID/command so it can be stopped and cleaned up deterministically&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example commands (serve 8080 from ns-myvpc-public)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;ip netns &lt;span class="nb"&gt;exec &lt;/span&gt;ns-myvpc-public &lt;span class="nb"&gt;nohup &lt;/span&gt;python3 &lt;span class="nt"&gt;-m&lt;/span&gt; http.server 8080 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /tmp/ns-myvpc-public-8080.log 2&amp;gt;&amp;amp;1 &amp;amp;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$!&lt;/span&gt;  &lt;span class="c"&gt;# PID recorded to metadata&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  stop-app
&lt;/h3&gt;

&lt;p&gt;Command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl stop-app myvpc public
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What happens&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Looks up the PID from metadata and terminates the app in the namespace&lt;/li&gt;
&lt;li&gt;Updates metadata&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Under the hood&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reads the stored PID/command and sends a graceful SIGTERM; falls back to stronger signals if needed&lt;/li&gt;
&lt;li&gt;Removes the application entry from the VPC metadata to keep state consistent&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example 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="nb"&gt;sudo kill&lt;/span&gt; &lt;span class="nt"&gt;-TERM&lt;/span&gt; &amp;lt;PID&amp;gt;
&lt;span class="c"&gt;# If needed after timeout: sudo kill -KILL &amp;lt;PID&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  enable-nat
&lt;/h3&gt;

&lt;p&gt;Command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl enable-nat myvpc &lt;span class="nt"&gt;--interface&lt;/span&gt; eth0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What happens&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enables IPv4 forwarding&lt;/li&gt;
&lt;li&gt;Adds NAT (MASQUERADE) and FORWARD rules to let selected subnets reach the internet via the host interface&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Under the hood&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Turns on kernel routing (net.ipv4.ip_forward=1)&lt;/li&gt;
&lt;li&gt;Installs an iptables NAT POSTROUTING MASQUERADE rule on the chosen egress interface, scoped to the VPC/subnets&lt;/li&gt;
&lt;li&gt;Adds FORWARD rules to permit established/related return traffic, keeping the ruleset minimal and safe&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example commands (egress via $IFACE)&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;IFACE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;ip route | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'/default/ {print $5; exit}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;sysctl &lt;span class="nt"&gt;-w&lt;/span&gt; net.ipv4.ip_forward&lt;span class="o"&gt;=&lt;/span&gt;1

&lt;span class="c"&gt;# NAT for the VPC CIDR&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;iptables &lt;span class="nt"&gt;-t&lt;/span&gt; nat &lt;span class="nt"&gt;-C&lt;/span&gt; POSTROUTING &lt;span class="nt"&gt;-s&lt;/span&gt; 10.10.0.0/16 &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$IFACE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-j&lt;/span&gt; MASQUERADE &lt;span class="se"&gt;\&lt;/span&gt;
  2&amp;gt;/dev/null &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;iptables &lt;span class="nt"&gt;-t&lt;/span&gt; nat &lt;span class="nt"&gt;-A&lt;/span&gt; POSTROUTING &lt;span class="nt"&gt;-s&lt;/span&gt; 10.10.0.0/16 &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$IFACE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-j&lt;/span&gt; MASQUERADE

&lt;span class="c"&gt;# Forwarding rules: allow outbound and established return&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;iptables &lt;span class="nt"&gt;-C&lt;/span&gt; FORWARD &lt;span class="nt"&gt;-i&lt;/span&gt; br-myvpc &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$IFACE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-j&lt;/span&gt; ACCEPT &lt;span class="se"&gt;\&lt;/span&gt;
  2&amp;gt;/dev/null &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;iptables &lt;span class="nt"&gt;-A&lt;/span&gt; FORWARD &lt;span class="nt"&gt;-i&lt;/span&gt; br-myvpc &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$IFACE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-j&lt;/span&gt; ACCEPT
&lt;span class="nb"&gt;sudo &lt;/span&gt;iptables &lt;span class="nt"&gt;-C&lt;/span&gt; FORWARD &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$IFACE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; br-myvpc &lt;span class="nt"&gt;-m&lt;/span&gt; state &lt;span class="nt"&gt;--state&lt;/span&gt; RELATED,ESTABLISHED &lt;span class="nt"&gt;-j&lt;/span&gt; ACCEPT &lt;span class="se"&gt;\&lt;/span&gt;
  2&amp;gt;/dev/null &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;iptables &lt;span class="nt"&gt;-A&lt;/span&gt; FORWARD &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$IFACE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; br-myvpc &lt;span class="nt"&gt;-m&lt;/span&gt; state &lt;span class="nt"&gt;--state&lt;/span&gt; RELATED,ESTABLISHED &lt;span class="nt"&gt;-j&lt;/span&gt; ACCEPT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  peer
&lt;/h3&gt;

&lt;p&gt;Command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl peer myvpc othervpc &lt;span class="nt"&gt;--allow-cidrs&lt;/span&gt; 10.10.1.0/24,10.20.1.0/24
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What happens&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creates a veth pair connecting br-myvpc and br-othervpc&lt;/li&gt;
&lt;li&gt;Adds iptables rules to allow only the specified CIDR pairs; everything else remains blocked&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Under the hood&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Connects the two VPC bridges with a veth pair to provide L2 reachability between VPCs&lt;/li&gt;
&lt;li&gt;Adds explicit host-level iptables rules to allow only the permitted CIDR ranges; a final DROP ensures least-privilege&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example commands (peer myvpc ↔ othervpc, allow public↔public only)&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;# Wire the bridges with a veth pair&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip &lt;span class="nb"&gt;link &lt;/span&gt;add pv-myvpc-otherv-a &lt;span class="nb"&gt;type &lt;/span&gt;veth peer name pv-myvpc-otherv-b
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip &lt;span class="nb"&gt;link set &lt;/span&gt;pv-myvpc-otherv-a master br-myvpc
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip &lt;span class="nb"&gt;link set &lt;/span&gt;pv-myvpc-otherv-b master br-othervpc
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip &lt;span class="nb"&gt;link set &lt;/span&gt;pv-myvpc-otherv-a up
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip &lt;span class="nb"&gt;link set &lt;/span&gt;pv-myvpc-otherv-b up

&lt;span class="c"&gt;# Allow only specific CIDR pairs&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;iptables &lt;span class="nt"&gt;-C&lt;/span&gt; vpc-myvpc   &lt;span class="nt"&gt;-s&lt;/span&gt; 10.10.1.0/24 &lt;span class="nt"&gt;-d&lt;/span&gt; 10.20.1.0/24 &lt;span class="nt"&gt;-j&lt;/span&gt; ACCEPT 2&amp;gt;/dev/null &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;iptables &lt;span class="nt"&gt;-A&lt;/span&gt; vpc-myvpc   &lt;span class="nt"&gt;-s&lt;/span&gt; 10.10.1.0/24 &lt;span class="nt"&gt;-d&lt;/span&gt; 10.20.1.0/24 &lt;span class="nt"&gt;-j&lt;/span&gt; ACCEPT
&lt;span class="nb"&gt;sudo &lt;/span&gt;iptables &lt;span class="nt"&gt;-C&lt;/span&gt; vpc-othervpc &lt;span class="nt"&gt;-s&lt;/span&gt; 10.20.1.0/24 &lt;span class="nt"&gt;-d&lt;/span&gt; 10.10.1.0/24 &lt;span class="nt"&gt;-j&lt;/span&gt; ACCEPT 2&amp;gt;/dev/null &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;iptables &lt;span class="nt"&gt;-A&lt;/span&gt; vpc-othervpc &lt;span class="nt"&gt;-s&lt;/span&gt; 10.20.1.0/24 &lt;span class="nt"&gt;-d&lt;/span&gt; 10.10.1.0/24 &lt;span class="nt"&gt;-j&lt;/span&gt; ACCEPT
&lt;span class="c"&gt;# (Default-deny handled by chain policy or fallback rules)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  apply-policy
&lt;/h3&gt;

&lt;p&gt;Command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl apply-policy myvpc policy_examples/example_ingress_egress_policy.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What happens&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Parses JSON and applies ingress/egress rules with iptables inside the target subnet namespace&lt;/li&gt;
&lt;li&gt;Uses rule comments to stay idempotent on re-apply&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Under the hood&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enters the subnet namespace and writes INPUT/OUTPUT rules with iptables&lt;/li&gt;
&lt;li&gt;Uses consistent comments/tags so re-applying the same policy updates rules without duplication&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example commands (inside ns-myvpc-public)&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;# Allow HTTP/HTTPS, deny SSH&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip netns &lt;span class="nb"&gt;exec &lt;/span&gt;ns-myvpc-public iptables &lt;span class="nt"&gt;-C&lt;/span&gt; INPUT &lt;span class="nt"&gt;-p&lt;/span&gt; tcp &lt;span class="nt"&gt;--dport&lt;/span&gt; 80  &lt;span class="nt"&gt;-j&lt;/span&gt; ACCEPT 2&amp;gt;/dev/null &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;ip netns &lt;span class="nb"&gt;exec &lt;/span&gt;ns-myvpc-public iptables &lt;span class="nt"&gt;-A&lt;/span&gt; INPUT &lt;span class="nt"&gt;-p&lt;/span&gt; tcp &lt;span class="nt"&gt;--dport&lt;/span&gt; 80  &lt;span class="nt"&gt;-j&lt;/span&gt; ACCEPT &lt;span class="nt"&gt;-m&lt;/span&gt; comment &lt;span class="nt"&gt;--comment&lt;/span&gt; vpcctl:allow-80
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip netns &lt;span class="nb"&gt;exec &lt;/span&gt;ns-myvpc-public iptables &lt;span class="nt"&gt;-C&lt;/span&gt; INPUT &lt;span class="nt"&gt;-p&lt;/span&gt; tcp &lt;span class="nt"&gt;--dport&lt;/span&gt; 443 &lt;span class="nt"&gt;-j&lt;/span&gt; ACCEPT 2&amp;gt;/dev/null &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;ip netns &lt;span class="nb"&gt;exec &lt;/span&gt;ns-myvpc-public iptables &lt;span class="nt"&gt;-A&lt;/span&gt; INPUT &lt;span class="nt"&gt;-p&lt;/span&gt; tcp &lt;span class="nt"&gt;--dport&lt;/span&gt; 443 &lt;span class="nt"&gt;-j&lt;/span&gt; ACCEPT &lt;span class="nt"&gt;-m&lt;/span&gt; comment &lt;span class="nt"&gt;--comment&lt;/span&gt; vpcctl:allow-443
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip netns &lt;span class="nb"&gt;exec &lt;/span&gt;ns-myvpc-public iptables &lt;span class="nt"&gt;-C&lt;/span&gt; INPUT &lt;span class="nt"&gt;-p&lt;/span&gt; tcp &lt;span class="nt"&gt;--dport&lt;/span&gt; 22  &lt;span class="nt"&gt;-j&lt;/span&gt; DROP   2&amp;gt;/dev/null &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;ip netns &lt;span class="nb"&gt;exec &lt;/span&gt;ns-myvpc-public iptables &lt;span class="nt"&gt;-A&lt;/span&gt; INPUT &lt;span class="nt"&gt;-p&lt;/span&gt; tcp &lt;span class="nt"&gt;--dport&lt;/span&gt; 22  &lt;span class="nt"&gt;-j&lt;/span&gt; DROP   &lt;span class="nt"&gt;-m&lt;/span&gt; comment &lt;span class="nt"&gt;--comment&lt;/span&gt; vpcctl:deny-22
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  list / inspect / delete
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;list: shows all VPCs (based on metadata files)&lt;/li&gt;
&lt;li&gt;inspect: pretty-prints full metadata (subnets, apps, NAT, peers, policies)&lt;/li&gt;
&lt;li&gt;delete: stops apps, removes namespaces, veths, bridge, and rules; then deletes metadata&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Under the hood&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;list: enumerates JSON files in .vpcctl_data to discover VPCs&lt;/li&gt;
&lt;li&gt;inspect: reads and pretty-prints the VPC's metadata to reflect actual state&lt;/li&gt;
&lt;li&gt;delete: reverses creation steps in a safe order (stop apps → tear down rules → remove namespaces/veths → delete bridge → purge metadata)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example 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="c"&gt;# list&lt;/span&gt;
&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-1&lt;/span&gt; .vpcctl_data | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s1"&gt;'s/^vpc_\(.*\)\.json$/\1/p'&lt;/span&gt;

&lt;span class="c"&gt;# inspect&lt;/span&gt;
jq &lt;span class="nb"&gt;.&lt;/span&gt; .vpcctl_data/vpc_myvpc.json

&lt;span class="c"&gt;# delete (excerpt)&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip netns del ns-myvpc-public &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true
sudo &lt;/span&gt;ip netns del ns-myvpc-private &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true
sudo &lt;/span&gt;ip &lt;span class="nb"&gt;link &lt;/span&gt;del br-myvpc &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true
sudo &lt;/span&gt;iptables &lt;span class="nt"&gt;-F&lt;/span&gt; vpc-myvpc 2&amp;gt;/dev/null &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true
sudo &lt;/span&gt;iptables &lt;span class="nt"&gt;-X&lt;/span&gt; vpc-myvpc 2&amp;gt;/dev/null &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true
rm&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; .vpcctl_data/vpc_myvpc.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Architecture Overview
&lt;/h2&gt;

&lt;p&gt;Single VPC&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%2Flq9hnpjjvqn5ixfmzrdf.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%2Flq9hnpjjvqn5ixfmzrdf.png" alt="Single VPC Architecture" width="798" height="328"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;VPC Peering (VPC ↔ VPC)&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%2Fpnspl8mzjoxi60zrsetj.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%2Fpnspl8mzjoxi60zrsetj.png" alt="VPC Peering Architecture" width="800" height="196"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Command Reference
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;create&lt;/td&gt;
&lt;td&gt;Create a new VPC&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo vpcctl create myvpc --cidr 10.10.0.0/16&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;add-subnet&lt;/td&gt;
&lt;td&gt;Add a subnet to a VPC&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo vpcctl add-subnet myvpc public --cidr 10.10.1.0/24&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;deploy-app&lt;/td&gt;
&lt;td&gt;Start HTTP server in subnet&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo vpcctl deploy-app myvpc public --port 8080&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;stop-app&lt;/td&gt;
&lt;td&gt;Stop running application&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo vpcctl stop-app myvpc public&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;enable-nat&lt;/td&gt;
&lt;td&gt;Enable internet access via NAT&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo vpcctl enable-nat myvpc --interface eth0&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;peer&lt;/td&gt;
&lt;td&gt;Connect two VPCs&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo vpcctl peer myvpc othervpc --allow-cidrs 10.10.1.0/24,10.20.1.0/24&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;apply-policy&lt;/td&gt;
&lt;td&gt;Apply firewall rules (JSON)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo vpcctl apply-policy myvpc policy.json&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;list&lt;/td&gt;
&lt;td&gt;List all VPCs&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo vpcctl list&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;inspect&lt;/td&gt;
&lt;td&gt;Show VPC metadata&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo vpcctl inspect myvpc&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;delete&lt;/td&gt;
&lt;td&gt;Delete a VPC&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo vpcctl delete myvpc&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;cleanup-all&lt;/td&gt;
&lt;td&gt;Delete all VPCs&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo vpcctl cleanup-all&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;verify&lt;/td&gt;
&lt;td&gt;Check for orphaned resources&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo vpcctl verify&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Troubleshooting Common Issues
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Issue 1: "Permission denied" or "Operation not permitted"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Symptom:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Error: Operation not permitted
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cause:&lt;/strong&gt; Not running with root privileges.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Always use sudo&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl create myapp &lt;span class="nt"&gt;--cidr&lt;/span&gt; 10.10.0.0/16
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Issue 2: "Cannot find command: ip"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Symptom:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Error: Cannot find required command: ip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cause:&lt;/strong&gt; Missing iproute2 package.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Ubuntu/Debian&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; iproute2

&lt;span class="c"&gt;# CentOS/RHEL&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;yum &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; iproute
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Issue 3: "Bridge already exists"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Symptom:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Error: RTNETLINK answers: File exists
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cause:&lt;/strong&gt; You already created a VPC with this name.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Option A: Use a different name&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl create myapp2 &lt;span class="nt"&gt;--cidr&lt;/span&gt; 10.10.0.0/16
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Option B: Delete the existing VPC first&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl delete myapp
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl create myapp &lt;span class="nt"&gt;--cidr&lt;/span&gt; 10.10.0.0/16
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Issue 4: Namespace Cannot Access Internet
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Symptom:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;ip netns &lt;span class="nb"&gt;exec &lt;/span&gt;ns-myapp-web curl &lt;span class="nt"&gt;-I&lt;/span&gt; http://1.1.1.1 | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-5&lt;/span&gt;
&lt;span class="c"&gt;# Hangs or fails&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Possible causes and solutions:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cause 1: NAT not enabled&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl enable-nat myapp &lt;span class="nt"&gt;--interface&lt;/span&gt; eth0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cause 2: Wrong host interface&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Find correct interface&lt;/span&gt;
ip route | &lt;span class="nb"&gt;grep &lt;/span&gt;default

&lt;span class="c"&gt;# Use the interface shown&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl enable-nat myapp &lt;span class="nt"&gt;--interface&lt;/span&gt; &amp;lt;correct-interface&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cause 3: Firewall blocking&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check iptables&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;iptables &lt;span class="nt"&gt;-t&lt;/span&gt; nat &lt;span class="nt"&gt;-L&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt;

&lt;span class="c"&gt;# Check for MASQUERADE rule&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;iptables &lt;span class="nt"&gt;-t&lt;/span&gt; nat &lt;span class="nt"&gt;-L&lt;/span&gt; POSTROUTING &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;MASQUERADE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cause 4: DNS not configured in namespace&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Copy resolv.conf into namespace&lt;/span&gt;
&lt;span class="nb"&gt;sudo mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /etc/netns/ns-myapp-web
&lt;span class="nb"&gt;sudo cp&lt;/span&gt; /etc/resolv.conf /etc/netns/ns-myapp-web/

&lt;span class="c"&gt;# Test again&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip netns &lt;span class="nb"&gt;exec &lt;/span&gt;ns-myapp-web curl &lt;span class="nt"&gt;-I&lt;/span&gt; http://1.1.1.1 | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Issue 5: Subnets Cannot Communicate
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Symptom:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# From subnet A trying to reach subnet B&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip netns &lt;span class="nb"&gt;exec &lt;/span&gt;ns-myapp-web curl http://10.10.2.2:5432
&lt;span class="c"&gt;# Connection refused or timeout&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Debugging steps:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Verify both subnets are in the same VPC&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl inspect myapp
&lt;span class="c"&gt;# Check that both subnets appear in the output&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2: Check if application is running in target subnet&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl inspect myapp | &lt;span class="nb"&gt;grep &lt;/span&gt;apps
&lt;span class="c"&gt;# Or&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip netns &lt;span class="nb"&gt;exec &lt;/span&gt;ns-myapp-database netstat &lt;span class="nt"&gt;-tlnp&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3: Verify routing&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check routing table in source namespace&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip netns &lt;span class="nb"&gt;exec &lt;/span&gt;ns-myapp-web ip route
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4: Check firewall rules&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check iptables in target namespace&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip netns &lt;span class="nb"&gt;exec &lt;/span&gt;ns-myapp-database iptables &lt;span class="nt"&gt;-L&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 5: Test basic connectivity (ping)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;ip netns &lt;span class="nb"&gt;exec &lt;/span&gt;ns-myapp-web ping &lt;span class="nt"&gt;-c&lt;/span&gt; 3 10.10.2.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Issue 6: "Cannot delete VPC: bridge is busy"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Symptom:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Error: RTNETLINK answers: Device or resource busy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cause:&lt;/strong&gt; Something is still using the bridge (running app, existing veth).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Force stop all apps first&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl cleanup-all

&lt;span class="c"&gt;# Or manually kill processes&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;pkill &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"ip netns exec ns-myapp"&lt;/span&gt;

&lt;span class="c"&gt;# Then try deleting again&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl delete myapp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Issue 7: Peered VPCs Cannot Communicate
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Symptom:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl peer vpc1 vpc2 &lt;span class="nt"&gt;--allow-cidrs&lt;/span&gt; 10.10.1.0/24,10.20.1.0/24
&lt;span class="c"&gt;# But curl between VPCs times out&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Debugging steps:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Verify peering exists&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl inspect vpc1 | &lt;span class="nb"&gt;grep &lt;/span&gt;peers
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl inspect vpc2 | &lt;span class="nb"&gt;grep &lt;/span&gt;peers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2: Check allowed CIDRs&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Make sure the source and destination subnets are in the allowed list&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl inspect vpc1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3: Check iptables rules&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;iptables &lt;span class="nt"&gt;-L&lt;/span&gt; vpc-vpc1 &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;span class="c"&gt;# Look for ACCEPT rules with peer CIDRs&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4: Test with specific IPs&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# From vpc1 subnet to vpc2 subnet&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip netns &lt;span class="nb"&gt;exec &lt;/span&gt;ns-vpc1-web curl http://10.20.1.2:8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Issue 8: High CPU Usage from Python HTTP Server
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Symptom:&lt;/strong&gt; System becomes slow after deploying multiple apps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cause:&lt;/strong&gt; Python's simple HTTP server is not designed for high performance.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Option A: Limit number of test apps&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Only deploy what you need&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl stop-app myapp web
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Option B: Use lighter alternatives&lt;/strong&gt;&lt;br&gt;
Instead of using &lt;code&gt;deploy-app&lt;/code&gt;, manually run a lighter server:&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;# Use busybox httpd (if available)&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip netns &lt;span class="nb"&gt;exec &lt;/span&gt;ns-myapp-web busybox httpd &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Issue 9: "Address already in use"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Symptom:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Error: bind: address already in use
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cause:&lt;/strong&gt; Port is already taken by another application.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Option 1: Use a different port&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl deploy-app myapp web &lt;span class="nt"&gt;--port&lt;/span&gt; 8081
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Option 2: Stop the conflicting app&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Find what's using the port&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;lsof &lt;span class="nt"&gt;-i&lt;/span&gt; :8080

&lt;span class="c"&gt;# Stop it&lt;/span&gt;
&lt;span class="nb"&gt;sudo kill&lt;/span&gt; &amp;lt;PID&amp;gt;

&lt;span class="c"&gt;# Or use vpcctl&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl stop-app myapp web
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Issue 10: Metadata File Corruption
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Symptom:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Error: JSON decode error
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cause:&lt;/strong&gt; Metadata file &lt;code&gt;.vpcctl_data/vpc_&amp;lt;name&amp;gt;.json&lt;/code&gt; got corrupted.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Option 1: Delete and recreate&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Remove corrupted metadata&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; .vpcctl_data/vpc_myapp.json

&lt;span class="c"&gt;# Recreate VPC&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl create myapp &lt;span class="nt"&gt;--cidr&lt;/span&gt; 10.10.0.0/16
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Option 2: Manual cleanup&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Remove namespace&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip netns del ns-myapp-web

&lt;span class="c"&gt;# Remove bridge&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip &lt;span class="nb"&gt;link &lt;/span&gt;del br-myapp

&lt;span class="c"&gt;# Remove metadata&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; .vpcctl_data/vpc_myapp.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Debugging Tips
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Enable verbose output:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Add debugging to see all iptables operations&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl create myapp &lt;span class="nt"&gt;--cidr&lt;/span&gt; 10.10.0.0/16 2&amp;gt;&amp;amp;1 | &lt;span class="nb"&gt;tee &lt;/span&gt;debug.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Check system logs:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# View kernel network messages&lt;/span&gt;
dmesg | &lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-50&lt;/span&gt;

&lt;span class="c"&gt;# System logs&lt;/span&gt;
journalctl &lt;span class="nt"&gt;-xe&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Verify bridge state:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# List all bridges&lt;/span&gt;
ip &lt;span class="nb"&gt;link &lt;/span&gt;show &lt;span class="nb"&gt;type &lt;/span&gt;bridge

&lt;span class="c"&gt;# Show bridge details&lt;/span&gt;
bridge &lt;span class="nb"&gt;link &lt;/span&gt;show
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Verify namespace state:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# List all namespaces&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip netns list

&lt;span class="c"&gt;# Show interfaces in a namespace&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip netns &lt;span class="nb"&gt;exec &lt;/span&gt;ns-myapp-web ip addr
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Verify iptables rules:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# NAT table&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;iptables &lt;span class="nt"&gt;-t&lt;/span&gt; nat &lt;span class="nt"&gt;-L&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt;

&lt;span class="c"&gt;# Filter table&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;iptables &lt;span class="nt"&gt;-L&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt;

&lt;span class="c"&gt;# Check specific chain&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;iptables &lt;span class="nt"&gt;-L&lt;/span&gt; vpc-myapp &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Complete Code Reference
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Metadata File Structure
&lt;/h3&gt;

&lt;p&gt;Every VPC has a JSON metadata file stored in &lt;code&gt;.vpcctl_data/vpc_&amp;lt;name&amp;gt;.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"myapp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"cidr"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"10.10.0.0/16"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"bridge"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"br-myapp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"chain"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vpc-myapp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"subnets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"web"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"cidr"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"10.10.1.0/24"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"ns"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ns-myapp-web"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"gw"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"10.10.1.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"host_ip"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"10.10.1.2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"veth"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"v-myapp-web"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"host_iptables"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"iptables"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"-A"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vpc-myapp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"-s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"10.10.0.0/16"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"-d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"10.10.0.0/16"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"-j"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ACCEPT"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"apps"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"ns"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ns-myapp-web"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"port"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"pid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;12345&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"cmd"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"ip"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"netns"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"exec"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ns-myapp-web"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"python3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"-m"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http.server"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"8080"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"peers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"peer_vpc"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"otherapp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"veth_a"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pv-myapp-other-va"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"veth_b"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pv-myapp-other-vb"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"allowed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"10.10.1.0/24"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"10.20.1.0/24"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"nat"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"interface"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"eth0"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Policy File Structure
&lt;/h3&gt;

&lt;p&gt;Policy files define ingress and egress firewall rules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"subnet"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"10.10.1.0/24"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ingress"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"port"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"protocol"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"allow"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"port"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;443&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"protocol"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"allow"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"port"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"protocol"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"deny"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"port"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3389&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"protocol"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"deny"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"egress"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"port"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"protocol"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"deny"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"port"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"protocol"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"allow"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"port"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;443&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"protocol"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"allow"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;subnet&lt;/code&gt;: CIDR of the subnet this policy applies to&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ingress&lt;/code&gt;: Rules for incoming traffic&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;egress&lt;/code&gt;: Rules for outgoing traffic&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;port&lt;/code&gt;: Port number&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;protocol&lt;/code&gt;: &lt;code&gt;tcp&lt;/code&gt;, &lt;code&gt;udp&lt;/code&gt;, or &lt;code&gt;icmp&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;action&lt;/code&gt;: &lt;code&gt;allow&lt;/code&gt; or &lt;code&gt;deny&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Common IP Address Ranges (CIDR)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Private IP ranges (safe to use):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;10.0.0.0/8&lt;/code&gt;: 10.0.0.0 to 10.255.255.255 (16 million IPs)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;172.16.0.0/12&lt;/code&gt;: 172.16.0.0 to 172.31.255.255 (1 million IPs)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;192.168.0.0/16&lt;/code&gt;: 192.168.0.0 to 192.168.255.255 (65,534 IPs)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;CIDR notation explained:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/8&lt;/code&gt;: 16,777,216 addresses&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/16&lt;/code&gt;: 65,536 addresses&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/24&lt;/code&gt;: 256 addresses&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/28&lt;/code&gt;: 16 addresses&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/32&lt;/code&gt;: 1 address&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;10.0.0.0/16&lt;/code&gt; = 10.0.0.1 to 10.0.255.254&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;192.168.1.0/24&lt;/code&gt; = 192.168.1.1 to 192.168.1.254&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;172.16.0.0/20&lt;/code&gt; = 172.16.0.1 to 172.16.15.254&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Quick Command Cheat Sheet
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create VPC&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl create &amp;lt;name&amp;gt; &lt;span class="nt"&gt;--cidr&lt;/span&gt; &amp;lt;ip-range&amp;gt;

&lt;span class="c"&gt;# Add subnet&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl add-subnet &amp;lt;vpc&amp;gt; &amp;lt;subnet-name&amp;gt; &lt;span class="nt"&gt;--cidr&lt;/span&gt; &amp;lt;ip-range&amp;gt;

&lt;span class="c"&gt;# Deploy test app&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl deploy-app &amp;lt;vpc&amp;gt; &amp;lt;subnet&amp;gt; &lt;span class="nt"&gt;--port&lt;/span&gt; &amp;lt;port&amp;gt;

&lt;span class="c"&gt;# Enable internet&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl enable-nat &amp;lt;vpc&amp;gt; &lt;span class="nt"&gt;--interface&lt;/span&gt; &amp;lt;iface&amp;gt;

&lt;span class="c"&gt;# Peer VPCs&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl peer &amp;lt;vpc1&amp;gt; &amp;lt;vpc2&amp;gt; &lt;span class="nt"&gt;--allow-cidrs&lt;/span&gt; &amp;lt;cidr1&amp;gt;,&amp;lt;cidr2&amp;gt;

&lt;span class="c"&gt;# Apply policy&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl apply-policy &amp;lt;vpc&amp;gt; &amp;lt;policy-file.json&amp;gt;

&lt;span class="c"&gt;# List VPCs&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl list

&lt;span class="c"&gt;# Inspect VPC&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl inspect &amp;lt;vpc&amp;gt;

&lt;span class="c"&gt;# Delete VPC&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl delete &amp;lt;vpc&amp;gt;

&lt;span class="c"&gt;# Test connectivity&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip netns &lt;span class="nb"&gt;exec &lt;/span&gt;ns-&amp;lt;vpc&amp;gt;-&amp;lt;subnet&amp;gt; curl http://&amp;lt;ip&amp;gt;:&amp;lt;port&amp;gt;

&lt;span class="c"&gt;# Run command in namespace&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip netns &lt;span class="nb"&gt;exec &lt;/span&gt;ns-&amp;lt;vpc&amp;gt;-&amp;lt;subnet&amp;gt; &amp;lt;&lt;span class="nb"&gt;command&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;# Check namespace IPs&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip netns &lt;span class="nb"&gt;exec &lt;/span&gt;ns-&amp;lt;vpc&amp;gt;-&amp;lt;subnet&amp;gt; ip addr

&lt;span class="c"&gt;# Check namespace routing&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip netns &lt;span class="nb"&gt;exec &lt;/span&gt;ns-&amp;lt;vpc&amp;gt;-&amp;lt;subnet&amp;gt; ip route

&lt;span class="c"&gt;# Check namespace firewall&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip netns &lt;span class="nb"&gt;exec &lt;/span&gt;ns-&amp;lt;vpc&amp;gt;-&amp;lt;subnet&amp;gt; iptables &lt;span class="nt"&gt;-L&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Best Practices
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Plan Your IP Address Space
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Bad:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Random, overlapping ranges&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl create app1 &lt;span class="nt"&gt;--cidr&lt;/span&gt; 10.0.0.0/24
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl create app2 &lt;span class="nt"&gt;--cidr&lt;/span&gt; 10.0.0.0/24  &lt;span class="c"&gt;# CONFLICT!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Good:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Organized, non-overlapping ranges&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl create dev &lt;span class="nt"&gt;--cidr&lt;/span&gt; 10.10.0.0/16
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl create staging &lt;span class="nt"&gt;--cidr&lt;/span&gt; 10.20.0.0/16
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl create prod &lt;span class="nt"&gt;--cidr&lt;/span&gt; 10.30.0.0/16
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Use Descriptive Names
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Bad:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl create vpc1 &lt;span class="nt"&gt;--cidr&lt;/span&gt; 10.0.0.0/16
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl add-subnet vpc1 sub1 &lt;span class="nt"&gt;--cidr&lt;/span&gt; 10.0.1.0/24
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Good:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl create ecommerce-app &lt;span class="nt"&gt;--cidr&lt;/span&gt; 10.0.0.0/16
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl add-subnet ecommerce-app web-tier &lt;span class="nt"&gt;--cidr&lt;/span&gt; 10.0.1.0/24
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl add-subnet ecommerce-app database &lt;span class="nt"&gt;--cidr&lt;/span&gt; 10.0.2.0/24
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Document Your Network
&lt;/h3&gt;

&lt;p&gt;Create a simple diagram:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;VPC: ecommerce-app (10.0.0.0/16)
├── web-tier (10.0.1.0/24) - Public, NAT enabled
│   └── nginx on 10.0.1.2:80
├── app-tier (10.0.2.0/24) - Private
│   └── node.js on 10.0.2.2:3000
└── database (10.0.3.0/24) - Private
    └── postgres on 10.0.3.2:5432
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Test Before Applying Policies
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# First, get everything working without restrictions&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl create &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;--cidr&lt;/span&gt; 10.99.0.0/16
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl add-subnet &lt;span class="nb"&gt;test &lt;/span&gt;web &lt;span class="nt"&gt;--cidr&lt;/span&gt; 10.99.1.0/24
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl deploy-app &lt;span class="nb"&gt;test &lt;/span&gt;web &lt;span class="nt"&gt;--port&lt;/span&gt; 8080

&lt;span class="c"&gt;# Test connectivity&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip netns &lt;span class="nb"&gt;exec &lt;/span&gt;ns-test-web curl localhost:8080

&lt;span class="c"&gt;# THEN apply policies&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl apply-policy &lt;span class="nb"&gt;test &lt;/span&gt;restrictive_policy.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Clean Up After Testing
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Always cleanup when done&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl delete test-vpc

&lt;span class="c"&gt;# Or nuke everything&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl cleanup-all
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6. Use Dry-Run First
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Preview before executing&lt;/span&gt;
vpcctl &lt;span class="nt"&gt;--dry-run&lt;/span&gt; create prod &lt;span class="nt"&gt;--cidr&lt;/span&gt; 10.30.0.0/16
&lt;span class="c"&gt;# Review the commands&lt;/span&gt;
&lt;span class="c"&gt;# Then run for real:&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;vpcctl create prod &lt;span class="nt"&gt;--cidr&lt;/span&gt; 10.30.0.0/16
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






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

&lt;h3&gt;
  
  
  Understanding Linux Networking
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Concepts to research:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Network namespaces&lt;/li&gt;
&lt;li&gt;Virtual Ethernet (veth) pairs&lt;/li&gt;
&lt;li&gt;Linux bridges&lt;/li&gt;
&lt;li&gt;iptables and netfilter&lt;/li&gt;
&lt;li&gt;IP routing and forwarding&lt;/li&gt;
&lt;li&gt;NAT and MASQUERADE&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;You now have a complete understanding of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What VPCs and subnets are&lt;/li&gt;
&lt;li&gt;Why we need network isolation&lt;/li&gt;
&lt;li&gt;How vpcctl works under the hood&lt;/li&gt;
&lt;li&gt;Every command and function in vpcctl&lt;/li&gt;
&lt;li&gt;How to build realistic network architectures&lt;/li&gt;
&lt;li&gt;How to troubleshoot common issues&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Remember:&lt;/strong&gt; vpcctl is a learning tool. It helps you understand cloud networking concepts without needing an AWS/Azure account. Once you master it, you'll find cloud provider VPCs much easier to work with!&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Author's Note:&lt;/strong&gt; This guide was written to be beginner-friendly. If you're reading this and something is unclear, that's a bug in the documentation, not in your understanding. Re-read the section, try the examples, and experiment!&lt;/p&gt;




&lt;h2&gt;
  
  
  Credits
&lt;/h2&gt;

&lt;p&gt;Author: DestinyObs&lt;br&gt;&lt;br&gt;
Tagline: iBuild | iDeploy | iSecure | iSustain&lt;br&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/DestinyObs/HNGi13-Stage4-vpcctl" rel="noopener noreferrer"&gt;https://github.com/DestinyObs/HNGi13-Stage4-vpcctl&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Happy networking!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>networking</category>
      <category>beginners</category>
      <category>tutorial</category>
      <category>linux</category>
    </item>
    <item>
      <title>Building a Self-Healing Blue/Green Deployment with Nginx &amp; Docker</title>
      <dc:creator>Destiny Obs</dc:creator>
      <pubDate>Sat, 25 Oct 2025 08:29:04 +0000</pubDate>
      <link>https://dev.to/destinyobs/building-a-self-healing-bluegreen-deployment-with-nginx-docker-3k12</link>
      <guid>https://dev.to/destinyobs/building-a-self-healing-bluegreen-deployment-with-nginx-docker-3k12</guid>
      <description>&lt;h2&gt;
  
  
  The 2:47 AM Lesson That Changed Everything
&lt;/h2&gt;

&lt;p&gt;It was &lt;strong&gt;2:47 AM&lt;/strong&gt;.&lt;br&gt;
Our backend service had gone quiet — not a hard crash, not an obvious error, just silence.&lt;br&gt;
Nginx sat waiting, clients kept retrying, and every second felt longer than the last.&lt;/p&gt;

&lt;p&gt;That was the night I learned the real definition of &lt;em&gt;downtime&lt;/em&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Downtime isn’t just when the server stops — it’s when users stop trusting your system.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So when the HNG DevOps Stage 2 task came, I didn’t just want to make a deployment work.&lt;br&gt;
I wanted to build something &lt;strong&gt;that heals itself&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;My goal was clear:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run &lt;strong&gt;two identical app containers&lt;/strong&gt; — Blue and Green.&lt;/li&gt;
&lt;li&gt;Let Nginx automatically fail over if one goes down.&lt;/li&gt;
&lt;li&gt;Keep responses clean, fast, and consistent.&lt;/li&gt;
&lt;li&gt;Never show a 5xx error again.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  What Blue/Green Deployment Really Means
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;Blue/Green Deployment&lt;/strong&gt; is a release strategy where two identical environments live side-by-side:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Environment&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Blue&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Active&lt;/td&gt;
&lt;td&gt;Serves live user traffic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Green&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Standby&lt;/td&gt;
&lt;td&gt;Runs silently, ready to take over&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;When Blue fails or you roll out an update, Green steps up instantly.&lt;br&gt;
Traffic switches without downtime.&lt;/p&gt;

&lt;p&gt;Think of it like a plane with two engines — both spinning, but only one giving thrust.&lt;br&gt;
If the active engine fails, you flip a switch, and the passengers never notice.&lt;br&gt;
That’s exactly what we achieve in DevOps terms:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Blue = Active upstream
Green = Backup upstream
Nginx = Pilot deciding which one should fly
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  My Three-Layer Architecture Stack
&lt;/h2&gt;

&lt;p&gt;Here’s the structure I built from the ground up:&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%2Fgist.github.com%2Fuser-attachments%2Fassets%2Fc6f14f33-4d6b-4a2b-92cb-5d7c0837d0ae" class="article-body-image-wrapper"&gt;&lt;img alt="image" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgist.github.com%2Fuser-attachments%2Fassets%2Fc6f14f33-4d6b-4a2b-92cb-5d7c0837d0ae" width="979" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All services live in a single &lt;strong&gt;Docker Network&lt;/strong&gt;, communicating through internal DNS.&lt;br&gt;
Nginx listens on &lt;strong&gt;port 8080&lt;/strong&gt;, while both app containers expose &lt;code&gt;/healthz&lt;/code&gt; and &lt;code&gt;/version&lt;/code&gt; endpoints.&lt;/p&gt;


&lt;h2&gt;
  
  
  Inside the Intelligence of Nginx Failover
&lt;/h2&gt;

&lt;p&gt;Failover magic starts inside the &lt;code&gt;upstream&lt;/code&gt; block of the Nginx configuration:&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%2Fgist.github.com%2Fuser-attachments%2Fassets%2F09bfcee3-c686-4cc7-af25-75736cb53b5c" class="article-body-image-wrapper"&gt;&lt;img alt="image" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgist.github.com%2Fuser-attachments%2Fassets%2F09bfcee3-c686-4cc7-af25-75736cb53b5c" width="596" height="130"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s break this down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;app_blue&lt;/code&gt;&lt;/strong&gt; is the primary server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;app_green&lt;/code&gt;&lt;/strong&gt; is marked as &lt;code&gt;backup&lt;/code&gt; — it stays idle until Blue fails.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;max_fails=1&lt;/code&gt;&lt;/strong&gt; means one failure is enough to demote Blue.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;fail_timeout=3s&lt;/code&gt;&lt;/strong&gt; decides how long Blue stays on the bench.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When Blue fails once within 3 seconds, Nginx instantly reroutes traffic to Green — no manual restart, no DNS propagation, no human intervention.&lt;/p&gt;

&lt;p&gt;That tiny keyword &lt;code&gt;backup&lt;/code&gt; turns Nginx from a static load balancer into a &lt;strong&gt;self-healing reverse proxy&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  Retry Logic — The Secret Behind Zero Downtime
&lt;/h2&gt;

&lt;p&gt;To make the transition invisible to users, I implemented this retry policy:&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%2Fgist.github.com%2Fuser-attachments%2Fassets%2F71c5dc74-96d7-4f68-a0e1-59048e6ae5c5" class="article-body-image-wrapper"&gt;&lt;img alt="image" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgist.github.com%2Fuser-attachments%2Fassets%2F71c5dc74-96d7-4f68-a0e1-59048e6ae5c5" width="544" height="69"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here’s what happens:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A request hits Blue.&lt;/li&gt;
&lt;li&gt;Blue delays or sends a 500.&lt;/li&gt;
&lt;li&gt;Nginx checks: “Is this retriable?”&lt;/li&gt;
&lt;li&gt;It retries &lt;strong&gt;once&lt;/strong&gt;, this time on Green.&lt;/li&gt;
&lt;li&gt;Green returns 200 OK — the user never notices.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It even retries &lt;strong&gt;POST&lt;/strong&gt; requests (&lt;code&gt;non_idempotent&lt;/code&gt;) safely.&lt;br&gt;
Because in real life, reliability &amp;gt; rigidity.&lt;/p&gt;


&lt;h2&gt;
  
  
  Docker Compose — Orchestrating Everything
&lt;/h2&gt;

&lt;p&gt;This was my &lt;code&gt;docker-compose.yml&lt;/code&gt; setup:&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%2Fgist.github.com%2Fuser-attachments%2Fassets%2Fe4c3bdc0-474d-4726-a831-05bdb0981302" class="article-body-image-wrapper"&gt;&lt;img alt="image" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgist.github.com%2Fuser-attachments%2Fassets%2Fe4c3bdc0-474d-4726-a831-05bdb0981302" width="639" height="818"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Two services (&lt;code&gt;app_blue&lt;/code&gt;, &lt;code&gt;app_green&lt;/code&gt;) are identical, except for color tags.&lt;br&gt;
Nginx uses environment variables like &lt;code&gt;ACTIVE_POOL&lt;/code&gt; to decide which one is live.&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%2Fgist.github.com%2Fuser-attachments%2Fassets%2F435e03b9-3f0d-4cbc-957d-4bdbfbc86607" class="article-body-image-wrapper"&gt;&lt;img alt="image" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgist.github.com%2Fuser-attachments%2Fassets%2F435e03b9-3f0d-4cbc-957d-4bdbfbc86607" width="1194" height="100"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  ⚙️ The Active Pool Switch Script
&lt;/h2&gt;

&lt;p&gt;To make switching seamless, I wrote a small shell script — &lt;code&gt;render-and-reload.sh&lt;/code&gt;.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgist.github.com%2Fuser-attachments%2Fassets%2F6b08797c-d429-463e-a8ab-5718141d1796" class="article-body-image-wrapper"&gt;&lt;img alt="image" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgist.github.com%2Fuser-attachments%2Fassets%2F6b08797c-d429-463e-a8ab-5718141d1796" width="807" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So with one command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-T&lt;/span&gt; nginx sh &lt;span class="nt"&gt;-lc&lt;/span&gt; &lt;span class="s1"&gt;'ACTIVE_POOL=green /opt/nginx/render-and-reload.sh'&lt;/span&gt;&lt;span class="s2"&gt;"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I can flip traffic instantly from Blue to Green — no rebuild, no downtime.&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%2Fgist.github.com%2Fuser-attachments%2Fassets%2F65a41989-25fc-41c0-96ce-3d1efff71831" class="article-body-image-wrapper"&gt;&lt;img alt="image" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgist.github.com%2Fuser-attachments%2Fassets%2F65a41989-25fc-41c0-96ce-3d1efff71831" width="1025" height="248"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Moment of Truth — Chaos Testing
&lt;/h2&gt;

&lt;p&gt;Once everything was running, I simulated failure with a secret robust script to break things.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bash scripts/verify.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The results were satisfying:&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%2Fgist.github.com%2Fuser-attachments%2Fassets%2F72275c80-7069-4fd9-8f19-429351efad6a" class="article-body-image-wrapper"&gt;&lt;img alt="image" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgist.github.com%2Fuser-attachments%2Fassets%2F72275c80-7069-4fd9-8f19-429351efad6a" width="512" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every request kept returning &lt;code&gt;200 OK&lt;/code&gt; even while Blue was being stressed.&lt;br&gt;
That’s not just a passing test — that’s &lt;strong&gt;trust preserved&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Concepts I Learned (Definitions for Interns Coming After Me)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Term&lt;/th&gt;
&lt;th&gt;Definition&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Upstream&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A group of backend servers that Nginx load-balances between.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Backup&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A server only used when primaries fail.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Failover&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Automatic switch to a standby system upon failure.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Healthcheck&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Automated test to ensure a container is alive and healthy.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Zero-Downtime Deployment&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Releasing new versions without interrupting service availability.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Why This Matters in the Real World
&lt;/h2&gt;

&lt;p&gt;In real production systems, even a minute of downtime can cost users, transactions, or trust.&lt;br&gt;
What this setup teaches is &lt;strong&gt;graceful failure&lt;/strong&gt; — planning for the moment things go wrong.&lt;/p&gt;

&lt;p&gt;And the best part?&lt;br&gt;
It’s all built with &lt;strong&gt;open-source tools&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docker for container orchestration&lt;/li&gt;
&lt;li&gt;Nginx for reverse proxy and failover&lt;/li&gt;
&lt;li&gt;Shell scripts for automation&lt;/li&gt;
&lt;li&gt;No fancy load balancer bills, no proprietary magic&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;This project wasn’t just about passing a task — it was a &lt;strong&gt;lesson in resilience&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In all my DevOps Practices i never thougth about this or implementing such cause they are many tools to do this&lt;br&gt;
I learned that DevOps isn’t only about deployment pipelines or automation scripts.&lt;br&gt;
It’s about ensuring that no matter what happens, your users stay unaffected.&lt;/p&gt;

&lt;p&gt;When the next 2:47 AM crash happens — your system won’t panic.&lt;br&gt;
It’ll &lt;em&gt;heal itself.&lt;/em&gt;&lt;br&gt;
&lt;strong&gt;GitHub Repo:&lt;/strong&gt; &lt;a href="https://github.com/DestinyObs/HNGi13-Stage2-Task" rel="noopener noreferrer"&gt;DestinyObs/HNGi13-Stage2-Task&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I’m DestinyObs| iDeploy | iSecure | iSustain&lt;/em&gt;&lt;/p&gt;




</description>
      <category>devops</category>
      <category>nginx</category>
      <category>productivity</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Building an AWS Microservices Infrastructure with Terraform — First Industry-like approach</title>
      <dc:creator>Destiny Obs</dc:creator>
      <pubDate>Wed, 28 May 2025 14:33:28 +0000</pubDate>
      <link>https://dev.to/destinyobs/building-an-aws-microservices-infrastructure-with-terraform-first-industry-like-approach-51jf</link>
      <guid>https://dev.to/destinyobs/building-an-aws-microservices-infrastructure-with-terraform-first-industry-like-approach-51jf</guid>
      <description>&lt;p&gt;It all started with food.&lt;br&gt;
Yeah… food.&lt;/p&gt;

&lt;p&gt;I was minding my business, doing my daily scroll through food content (don’t judge), when a friend dropped a Twitter link.&lt;br&gt;
&lt;em&gt;“See what I’m working on,”&lt;/em&gt; he said.&lt;br&gt;
Spoiler alert: it was &lt;strong&gt;not&lt;/strong&gt; jollof rice.&lt;/p&gt;

&lt;p&gt;It was a Task definition thread on setting up an AWS infrastructure using Terraform. I had never done it before. But hey, curiosity (and maybe hunger) kicked in. So I tried it.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Why This Article Tastes Different&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Let’s be honest — I’m not your go-to “10 years in the trenches” DevOps guy. I’m just someone who’s curious, hungry (literally and metaphorically), and absolutely allergic to boring tech content.&lt;/p&gt;

&lt;p&gt;This is my &lt;strong&gt;first clean, modular, industry-grade&lt;/strong&gt; Infrastructure as Code setup.&lt;br&gt;
Yes, something might break.&lt;br&gt;
Yes, you’ll probably fix something when you try it yourself.&lt;br&gt;
And yes, I’m totally okay with that.&lt;/p&gt;

&lt;p&gt;So grab a snack and vibe with me as we walk through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How I planned the whole setup (inspired by that wild Twitter link)&lt;/li&gt;
&lt;li&gt;Why Terraform modules became my besties&lt;/li&gt;
&lt;li&gt;The microservices app I didn’t containerize — but my friend did&lt;/li&gt;
&lt;li&gt;My “trust me, it works” folder structure&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Project Overview&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Here’s what I built: an AWS infrastructure to host a microservices-based app made up of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;React frontend&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Two APIs — one in &lt;strong&gt;Node.js&lt;/strong&gt;, one in &lt;strong&gt;Go&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;PostgreSQL&lt;/strong&gt; database&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;Python load generator&lt;/strong&gt; to keep things spicy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All deployed on &lt;strong&gt;ECS Fargate&lt;/strong&gt;, orchestrated by the real MVP: &lt;strong&gt;Terraform&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Architecture Flow&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Public Subnets&lt;/strong&gt; – for the ALB to accept traffic like a bouncer at an exclusive party.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Private Subnets&lt;/strong&gt; – where ECS and RDS live in peace, away from public scrutiny.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secrets Manager&lt;/strong&gt; – because plain-text passwords are a crime.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CloudWatch&lt;/strong&gt; – watching so I don’t have to.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ALB → ECS → RDS&lt;/strong&gt; – like a well-oiled relay team.&lt;/li&gt;
&lt;/ul&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%2Fwvcxegqpm6clklteq6mp.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%2Fwvcxegqpm6clklteq6mp.png" alt="Image description" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Folder Structure&lt;/strong&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
├── &lt;span class="nb"&gt;env&lt;/span&gt;/
│   └── dev/
│       ├── backend.tf         &lt;span class="c"&gt;# S3 state backend&lt;/span&gt;
│       ├── main.tf            &lt;span class="c"&gt;# Main config&lt;/span&gt;
│       ├── outputs.tf         &lt;span class="c"&gt;# What Terraform spits out&lt;/span&gt;
│       ├── providers.tf       &lt;span class="c"&gt;# AWS provider config&lt;/span&gt;
│       ├── terraform.tfvars   &lt;span class="c"&gt;# Your environment’s juicy secrets&lt;/span&gt;
│       └── variables.tf       &lt;span class="c"&gt;# Input variables&lt;/span&gt;
├── modules/
│   ├── alb/                   &lt;span class="c"&gt;# Load balancer setup&lt;/span&gt;
│   ├── ecr/                   &lt;span class="c"&gt;# ECR repos&lt;/span&gt;
│   ├── ecs/                   &lt;span class="c"&gt;# ECS cluster&lt;/span&gt;
│   ├── monitoring/            &lt;span class="c"&gt;# CloudWatch logs + alarms&lt;/span&gt;
│   ├── rds/                   &lt;span class="c"&gt;# PostgreSQL config&lt;/span&gt;
│   ├── secrets_manager/       &lt;span class="c"&gt;# For hiding your sins (passwords)&lt;/span&gt;
│   ├── security_groups/       &lt;span class="c"&gt;# Fine-grained access control&lt;/span&gt;
│   └── vpc/                   &lt;span class="c"&gt;# VPC + networking&lt;/span&gt;
├── .gitignore
└── README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Modular. Reusable. Tidy. Just like the way I my kitchen looks.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Modules Breakdown&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  VPC
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Sets up networking: public + private subnets, NAT, IGW, route tables.&lt;/li&gt;
&lt;li&gt;Outputs subnet IDs for other modules to use.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;ALB talks to the world.&lt;/li&gt;
&lt;li&gt;ECS talks to ALB.&lt;/li&gt;
&lt;li&gt;RDS? Strictly ECS only. No loose lips.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ECR
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;One repo per service: frontend, node API, go API, load generator.&lt;/li&gt;
&lt;li&gt;Push your Docker images here. Clean, secure, efficient.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  RDS
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;PostgreSQL DB in a private subnet.&lt;/li&gt;
&lt;li&gt;Encrypted. Multi-AZ. Passwords stored in Secrets Manager.&lt;/li&gt;
&lt;li&gt;Fancy, right?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Secrets Manager
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;All environment variables + credentials stored here as a single JSON blob.&lt;/li&gt;
&lt;li&gt;Because leaking secrets is so 2015.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ECS
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Fargate cluster — because I don’t babysit EC2s.&lt;/li&gt;
&lt;li&gt;(Tasks and services coming soon.)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ALB
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;In public subnet, routing traffic to ECS via target groups.&lt;/li&gt;
&lt;li&gt;Listener rules? We’ll wire those up later.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Monitoring
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;CloudWatch log groups + a CPU alarm.&lt;/li&gt;
&lt;li&gt;(Still cooking memory + RDS alarms.)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How the App Connects (from Docker Compose to ECS)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;My friend had the app in Docker Compose.&lt;br&gt;
I mapped each service to a future ECS task:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Client (React)&lt;/strong&gt; → ALB → ECS Task&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Node API &amp;amp; Go API&lt;/strong&gt; → ALB paths → ECS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PostgreSQL&lt;/strong&gt; already containerized, now replaced with managed RDS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Load Generator&lt;/strong&gt; → ECS task to simulate real-world chaos&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All environment variables are injected from &lt;strong&gt;Secrets Manager&lt;/strong&gt;.&lt;br&gt;
Container images are stored in &lt;strong&gt;ECR&lt;/strong&gt;, pulled at deploy.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Deployment Steps&lt;/strong&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Clone the repo&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/DestinyObs/terraform-ecs.git
&lt;span class="nb"&gt;cd &lt;/span&gt;terraform-ecs/env/dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Initialize Terraform&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

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

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Preview your infrastructure&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

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

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Apply the config&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

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

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Destroy it when you’re done playing God&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;What’s Next (on My DevOps Menu)&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Add ECS task definitions + services&lt;/li&gt;
&lt;li&gt;ALB listener rules for routing by path (&lt;code&gt;/api&lt;/code&gt;, &lt;code&gt;/client&lt;/code&gt;, etc.)&lt;/li&gt;
&lt;li&gt;Memory + DB monitoring&lt;/li&gt;
&lt;li&gt;SSM integration for better secret hygiene&lt;/li&gt;
&lt;li&gt;Full CI/CD pipeline for image builds + infra deploys&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Final Thoughts&lt;/strong&gt;
&lt;/h2&gt;

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

&lt;ul&gt;
&lt;li&gt;curiosity&lt;/li&gt;
&lt;li&gt;hunger&lt;/li&gt;
&lt;li&gt;pure Terraform joy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’re just starting with cloud infra, this is a fun sandbox.&lt;br&gt;
If you’re an experienced engineer, fork it and show me what I missed.&lt;/p&gt;

&lt;p&gt;The goal isn’t perfection. The goal is progress — and maybe a snack break along the way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try the code or roast my setup here:&lt;/strong&gt;&lt;br&gt;
 &lt;a href="https://github.com/DestinyObs/terraform-ecs" rel="noopener noreferrer"&gt;GitHub: DestinyObs/terraform-ecs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I’m DestinyObs&lt;/em&gt;&lt;br&gt;
&lt;em&gt;iDeploy | iSecure | iSustain | iLikeFood&lt;/em&gt;&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>devops</category>
      <category>aws</category>
      <category>newbie</category>
    </item>
    <item>
      <title>Why This Matters: Streamlined Deployment for ASP.NET Core on IIS</title>
      <dc:creator>Destiny Obs</dc:creator>
      <pubDate>Mon, 14 Apr 2025 14:56:21 +0000</pubDate>
      <link>https://dev.to/destinyobs/why-this-matters-streamlined-deployment-for-aspnet-core-on-iis-1jie</link>
      <guid>https://dev.to/destinyobs/why-this-matters-streamlined-deployment-for-aspnet-core-on-iis-1jie</guid>
      <description>&lt;p&gt;Deploying web applications manually on a Windows Server can be &lt;strong&gt;tedious, error-prone, and time-consuming&lt;/strong&gt;. Every new server setup requires multiple steps — installing IIS, configuring app pools, setting permissions, publishing code, assigning ports, and so on.&lt;/p&gt;

&lt;p&gt;What if you could skip all of that?&lt;/p&gt;

&lt;p&gt;What if you could go from &lt;strong&gt;zero to a fully running ASP.NET Core application&lt;/strong&gt; hosted on IIS with just one command?&lt;/p&gt;

&lt;p&gt;That’s exactly what this PowerShell script is designed to do.&lt;/p&gt;




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

&lt;p&gt;We’re automating the entire process of deploying an &lt;strong&gt;ASP.NET Core web application (SGBookPortal)&lt;/strong&gt; onto &lt;strong&gt;IIS (Internet Information Services)&lt;/strong&gt; on a Windows Server machine.&lt;/p&gt;

&lt;p&gt;By the end of the script, you’ll have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;IIS installed and ready&lt;/li&gt;
&lt;li&gt;Your application cloned from GitHub&lt;/li&gt;
&lt;li&gt;Code built and published to the right folder&lt;/li&gt;
&lt;li&gt;Folder permissions properly set&lt;/li&gt;
&lt;li&gt;An IIS site and application pool fully configured&lt;/li&gt;
&lt;li&gt;Your app running and accessible via &lt;code&gt;http://localhost:&amp;lt;your_port&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  How This Would Be Done Manually on Windows Server
&lt;/h2&gt;

&lt;p&gt;Here’s a step-by-step explanation of what this deployment would look like if you were to &lt;strong&gt;do it manually without automation&lt;/strong&gt;:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 1: Launch PowerShell as Administrator&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Why? Most IIS, system configurations, and software installations require elevated privileges.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Step 2: Install IIS&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Go to &lt;strong&gt;Server Manager &amp;gt; Add Roles and Features&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Select the &lt;strong&gt;Web Server (IIS)&lt;/strong&gt; role&lt;/li&gt;
&lt;li&gt;Enable management tools like &lt;strong&gt;IIS Management Console&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Complete the wizard and restart if required&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Purpose: IIS is the Windows component that will host and serve our ASP.NET Core site.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Step 3: Install Git&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Download and install Git from &lt;a href="https://git-scm.com/download/win" rel="noopener noreferrer"&gt;https://git-scm.com/download/win&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
This is needed to clone the code repository.&lt;/p&gt;


&lt;h3&gt;
  
  
  *&lt;em&gt;Step 4: Install .NET SDK and Hosting Bundle *&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;Install the appropriate &lt;strong&gt;.NET SDK version&lt;/strong&gt; from &lt;a href="https://dotnet.microsoft.com/download" rel="noopener noreferrer"&gt;https://dotnet.microsoft.com/download&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Purpose: We use the SDK to &lt;strong&gt;build and publish&lt;/strong&gt; the ASP.NET Core project to a deployable format.&lt;/p&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;Step 5: Clone the Repository&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Open PowerShell or Git Bash&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;git clone &amp;lt;repo_url&amp;gt;&lt;/code&gt; to download the project into your local file system&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;Step 6: Create Web Root Directory&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Manually go to &lt;code&gt;C:\inetpub\wwwroot&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Create a folder named &lt;code&gt;sgbookportal&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;This will serve as the deployment folder for the app files&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;Step 7: Publish the ASP.NET Core App&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Navigate to the project folder&lt;/li&gt;
&lt;li&gt;Run:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;dotnet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;publish&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;BookPortel.csproj&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Release&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-o&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;C:\inetpub\wwwroot\sgbookportal&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This compiles the application and outputs the binaries, views, configs, and dependencies needed for production.&lt;/p&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;Step 8: Set Folder Permissions&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Right-click the deployment folder&lt;/li&gt;
&lt;li&gt;Go to &lt;strong&gt;Properties &amp;gt; Security&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Grant &lt;strong&gt;Read and Execute&lt;/strong&gt; permission to the user group: &lt;code&gt;IIS_IUSRS&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Purpose: IIS worker process needs permissions to serve the app from this directory.&lt;/p&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;Step 9: Assign an Available Port&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Since IIS sites bind to specific ports, you need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check which ports are already in use (especially 80/443)&lt;/li&gt;
&lt;li&gt;Pick an unused one (e.g., 8081)&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;Step 10: Create IIS Website and Application Pool&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Open &lt;strong&gt;IIS Manager&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Right-click &lt;strong&gt;Sites &amp;gt; Add Website&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Site name: &lt;code&gt;SGBookPortal&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Physical path: &lt;code&gt;C:\inetpub\wwwroot\sgbookportal&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Port: e.g., &lt;code&gt;8081&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click OK&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: For ASP.NET Core, &lt;strong&gt;App Pool should be configured with “No Managed Code”&lt;/strong&gt; since .NET Core apps run as standalone processes (Kestrel).&lt;br&gt;&lt;br&gt;
However, &lt;strong&gt;IIS auto-generates and manages this App Pool&lt;/strong&gt; when you create the site via PowerShell, so no need to configure it manually.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;Step 11: Start the Website&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;From &lt;strong&gt;IIS Manager&lt;/strong&gt;, select the site and click &lt;strong&gt;Start&lt;/strong&gt; in the right-hand panel.&lt;br&gt;&lt;br&gt;
Visit &lt;code&gt;http://localhost:8081/swagger/index.html&lt;/code&gt; to test the app.&lt;/p&gt;


&lt;h2&gt;
  
  
  Now Let's Explain the Script in Bits
&lt;/h2&gt;

&lt;p&gt;Now we’ll walk through and explain each part of the script — line by line.&lt;/p&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;1. Ensure Script is Run as Administrator&lt;/strong&gt;
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;Security.Principal.WindowsPrincipal&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"This script must be run as Administrator."&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ForegroundColor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Red&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="kr"&gt;exit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Checks if the current PowerShell session is running with admin privileges. If not, it exits to prevent permission errors.&lt;/p&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;2. Install IIS&lt;/strong&gt;
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Install-WindowsFeature&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Web-Server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-IncludeManagementTools&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Installs the &lt;strong&gt;Web-Server (IIS)&lt;/strong&gt; role along with tools like the IIS Manager GUI.&lt;/p&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;3. Ensure Git is Installed&lt;/strong&gt;
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Get-Command&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Git is not installed..."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Checks for Git. If not available, asks the user to install it manually.&lt;/p&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;4. Ensure .NET SDK is Installed&lt;/strong&gt;
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Get-Command&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;dotnet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;".NET SDK is not installed..."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Checks for the &lt;code&gt;dotnet&lt;/code&gt; CLI which is used to build and publish .NET apps.&lt;/p&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;5. Define Variables&lt;/strong&gt;
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$repoUrl&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://github.com/softwaregurukulamdevops/SGbookportal.git"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$clonePath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"C:\SGbookportal"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$sitePath&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"C:\inetpub\wwwroot\sgbookportal"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$siteName&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SGBookPortal"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$poolName&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SGBookPortalPool"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;These variables define:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The GitHub repo URL&lt;/li&gt;
&lt;li&gt;Local directory to clone the repo&lt;/li&gt;
&lt;li&gt;Final publish target (IIS web root)&lt;/li&gt;
&lt;li&gt;IIS site and app pool names&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;6. Clone the Repository&lt;/strong&gt;
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Test-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$clonePath&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;clone&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$repoUrl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$clonePath&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Clones the codebase from GitHub if it doesn't already exist.&lt;/p&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;7. Create Web Root Directory&lt;/strong&gt;
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;New-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$sitePath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ItemType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Directory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Force&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Creates the folder under IIS's &lt;code&gt;wwwroot&lt;/code&gt; where the app will live.&lt;/p&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;8. Publish the App&lt;/strong&gt;
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;dotnet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;publish&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$clonePath&lt;/span&gt;&lt;span class="s2"&gt;\BookPortel\BookPortel.csproj"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Release&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-o&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$sitePath&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Builds the app in &lt;code&gt;Release&lt;/code&gt; mode and deploys it to &lt;code&gt;$sitePath&lt;/code&gt;.&lt;/p&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;9. Set IIS Permissions&lt;/strong&gt;
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;icacls&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$sitePath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/grant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"IIS_IUSRS:(OI)(CI)RX"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/T&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Grants &lt;strong&gt;Read/Execute&lt;/strong&gt; permissions to IIS user groups on the deployed folder recursively.&lt;/p&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;10. Assign Available Port&lt;/strong&gt;
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$startingPort&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$usedPorts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Get-NetTCPConnection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-State&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Listen&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LocalPort&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$port&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$startingPort&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kr"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$usedPorts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-contains&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$port&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Checks for an unused port starting from 80 and selects the first one available.&lt;/p&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;11. Configure IIS&lt;/strong&gt;
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Import-Module&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;WebAdministration&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Loads IIS management commands into the session.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Get-Website&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Where-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-eq&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$siteName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Remove-Website&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$siteName&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Removes any existing IIS site with the same name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Test-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"IIS:\AppPools\&lt;/span&gt;&lt;span class="nv"&gt;$poolName&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;New-WebAppPool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$poolName&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Set-ItemProperty&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"managedRuntimeVersion"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Creates an App Pool with &lt;strong&gt;No Managed Code&lt;/strong&gt;, suitable for .NET Core apps.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;New-Website&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$siteName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Port&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$port&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-PhysicalPath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$sitePath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ApplicationPool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$poolName&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Creates a new IIS site, bound to the selected port, and linked to the specified app pool.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;12. Start the Website&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Start-Website&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$siteName&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Starts the newly created site.&lt;br&gt;&lt;br&gt;
User is informed they can access the app at &lt;code&gt;http://localhost:$port/swagger/index.html&lt;/code&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;This script removes all the manual overhead of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Installing necessary tools&lt;/li&gt;
&lt;li&gt;Publishing the application&lt;/li&gt;
&lt;li&gt;Setting permissions&lt;/li&gt;
&lt;li&gt;Configuring IIS (sites + app pool)&lt;/li&gt;
&lt;li&gt;Starting the hosted service&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;
  
  
  Troubleshooting IIS Deployment Issues for ASP.NET Core
&lt;/h3&gt;

&lt;p&gt;During my deployment of an ASP.NET Core application to IIS, I encountered two major errors that I think are common and worth documenting for others:&lt;/p&gt;


&lt;h4&gt;
  
  
  &lt;strong&gt;Error 1: While Performing Authentication Settings in IIS&lt;/strong&gt;
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;There was an error while performing this operation.
Details:
Filename: \\?\C:\users\...\.config
Error: 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2F55vrysgmql9yjofot5e1.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%2F55vrysgmql9yjofot5e1.png" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Error 2: HTTP Error 500.19 – Internal Server Error&lt;/strong&gt;
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The requested page cannot be accessed because the related configuration data for the page is invalid.
Error Code: 0x8007000d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fnf5j5vrsh56oew6kx96t.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%2Fnf5j5vrsh56oew6kx96t.png" alt="Image description" width="800" height="422"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h3&gt;
  
  
  What to Check When You See These Errors:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Check for &lt;code&gt;web.config&lt;/code&gt; File&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to your published folder (e.g., &lt;code&gt;bin\release\net8.0\publish&lt;/code&gt;) and &lt;strong&gt;make sure the file is named &lt;code&gt;web.config&lt;/code&gt; and not just &lt;code&gt;web&lt;/code&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;IIS requires a proper &lt;code&gt;web.config&lt;/code&gt; file to know how to run your ASP.NET Core app. If it’s missing or malformed, IIS won't know how to serve your application.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Check if the .NET Core Hosting Bundle is Installed Correctly&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;These types of errors can also mean that &lt;strong&gt;the ASP.NET Core Hosting Bundle is either not installed or not configured correctly&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;This bundle allows IIS to run ASP.NET Core applications using the in-process hosting model.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;Recommended Fix&lt;/strong&gt;:
&lt;/h3&gt;

&lt;p&gt;If you run into these kinds of issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Start Fresh&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uninstall any previous hosting bundle installations if you're unsure of their integrity.&lt;/li&gt;
&lt;li&gt;Reinstall the latest &lt;strong&gt;.NET Core Hosting Bundle&lt;/strong&gt; compatible with your app version.
&amp;gt; You can download it from &lt;a href="https://dotnet.microsoft.com/en-us/download/dotnet" rel="noopener noreferrer"&gt;Microsoft's official .NET download page&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🛠️ &lt;strong&gt;Re-Publish Your Application&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use Visual Studio or &lt;code&gt;dotnet publish&lt;/code&gt; again to regenerate the files, ensuring the &lt;code&gt;web.config&lt;/code&gt; is created properly.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;
  
  
  In Summary
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;These are the errors I personally faced during deployment. If you run into something similar, start by checking the &lt;code&gt;web.config&lt;/code&gt; presence and reinstalling the .NET Hosting Bundle. That’s what worked for me!&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Deploys the SGBookPortal ASP.NET Core application to IIS&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Step 1: Ensure script is run as Administrator&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;Security.Principal.WindowsPrincipal&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Security.Principal.WindowsIdentity&lt;/span&gt;&lt;span class="p"&gt;]::&lt;/span&gt;&lt;span class="n"&gt;GetCurrent&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsInRole&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;Security.Principal.WindowsBuiltinRole&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Administrator"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"This script must be run as Administrator."&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ForegroundColor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Red&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="kr"&gt;exit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Step 2: Install IIS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Installing IIS..."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kr"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Install-WindowsFeature&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Web-Server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-IncludeManagementTools&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ErrorAction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Stop&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Failed to install IIS: &lt;/span&gt;&lt;span class="bp"&gt;$_&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ForegroundColor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Red&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="kr"&gt;exit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Step 3: Check for Git&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Get-Command&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ErrorAction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SilentlyContinue&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Git is not installed. Install Git from https://git-scm.com/download/win and rerun the script."&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ForegroundColor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Red&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="kr"&gt;exit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Step 4: Check for .NET SDK&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Get-Command&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;dotnet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ErrorAction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SilentlyContinue&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;".NET SDK is not installed. Install from https://dotnet.microsoft.com/download and rerun the script."&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ForegroundColor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Red&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="kr"&gt;exit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Step 5: Define variables&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$repoUrl&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://github.com/softwaregurukulamdevops/SGbookportal.git"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$clonePath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"C:\SGbookportal"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$sitePath&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"C:\inetpub\wwwroot\sgbookportal"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$siteName&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SGBookPortal"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$poolName&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SGBookPortalPool"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Step 6: Clone the repository if not already present&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Test-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$clonePath&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="kr"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Cloning repository..."&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;clone&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$repoUrl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$clonePath&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Repository clone failed: &lt;/span&gt;&lt;span class="bp"&gt;$_&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ForegroundColor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Red&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="kr"&gt;exit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Repository already exists. Skipping clone."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Step 7: Create web root directory&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Test-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$sitePath&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="kr"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Creating web root directory..."&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;New-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$sitePath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ItemType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Directory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Force&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Failed to create web root directory: &lt;/span&gt;&lt;span class="bp"&gt;$_&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ForegroundColor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Red&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="kr"&gt;exit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Step 8: Publish the ASP.NET Core project&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kr"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Publishing the application..."&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;dotnet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;publish&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$clonePath&lt;/span&gt;&lt;span class="s2"&gt;\BookPortel\BookPortel.csproj"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Release&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-o&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$sitePath&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Publish failed: &lt;/span&gt;&lt;span class="bp"&gt;$_&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ForegroundColor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Red&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="kr"&gt;exit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Step 9: Grant IIS read/execute permissions&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kr"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Setting permissions..."&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;icacls&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$sitePath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/grant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"IIS_IUSRS:(OI)(CI)RX"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/T&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Out-Null&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Failed to set folder permissions: &lt;/span&gt;&lt;span class="bp"&gt;$_&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ForegroundColor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Red&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="kr"&gt;exit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Step 10: Check and assign available port (start from 80)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$startingPort&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$usedPorts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Get-NetTCPConnection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-State&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Listen&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LocalPort&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Sort-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Unique&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$port&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$startingPort&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kr"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$usedPorts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-contains&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nv"&gt;$port&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Selected port: &lt;/span&gt;&lt;span class="nv"&gt;$port&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Step 11: Configure IIS - Remove existing site and create app pool&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Import-Module&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;WebAdministration&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Remove existing site if it exists&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Get-Website&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Where-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-eq&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$siteName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="kr"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Removing existing site '&lt;/span&gt;&lt;span class="nv"&gt;$siteName&lt;/span&gt;&lt;span class="s2"&gt;'..."&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;Remove-Website&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$siteName&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Failed to remove existing IIS site: &lt;/span&gt;&lt;span class="bp"&gt;$_&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ForegroundColor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Red&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="kr"&gt;exit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Create App Pool (No Managed Code for .NET Core)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Test-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"IIS:\AppPools\&lt;/span&gt;&lt;span class="nv"&gt;$poolName&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;New-WebAppPool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$poolName&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Set-ItemProperty&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"IIS:\AppPools\&lt;/span&gt;&lt;span class="nv"&gt;$poolName&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"managedRuntimeVersion"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Create new IIS website&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kr"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Creating IIS site '&lt;/span&gt;&lt;span class="nv"&gt;$siteName&lt;/span&gt;&lt;span class="s2"&gt;'..."&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;New-Website&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$siteName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Port&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$port&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-PhysicalPath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$sitePath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ApplicationPool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$poolName&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Failed to create IIS site: &lt;/span&gt;&lt;span class="bp"&gt;$_&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ForegroundColor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Red&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="kr"&gt;exit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Step 12: Start the website&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kr"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Start-Website&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$siteName&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;`n&lt;/span&gt;&lt;span class="s2"&gt;Deployment completed successfully."&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"You can access the application at: http://localhost:&lt;/span&gt;&lt;span class="nv"&gt;$port&lt;/span&gt;&lt;span class="s2"&gt;/swagger/index.html&lt;/span&gt;&lt;span class="se"&gt;`n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Failed to start IIS site: &lt;/span&gt;&lt;span class="bp"&gt;$_&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ForegroundColor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Red&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="kr"&gt;exit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

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

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>Automating Cloud Deployments (AWS): Terraform, Docker, and CI/CD</title>
      <dc:creator>Destiny Obs</dc:creator>
      <pubDate>Mon, 31 Mar 2025 18:44:00 +0000</pubDate>
      <link>https://dev.to/destinyobs/automating-cloud-deployments-aws-terraform-docker-and-cicd-3i1n</link>
      <guid>https://dev.to/destinyobs/automating-cloud-deployments-aws-terraform-docker-and-cicd-3i1n</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Project Overview&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Imagine a world where infrastructure provisions itself, deployments happen at the speed of light, and applications run seamlessly in containers. Sounds like DevOps heaven, right? Well, that’s exactly what we’ve built! This project is a &lt;strong&gt;Flask API&lt;/strong&gt; running on &lt;strong&gt;AWS EC2&lt;/strong&gt;, with a &lt;strong&gt;PostgreSQL database&lt;/strong&gt;, fully automated using Terraform, Docker, and GitHub Actions. No more manual configurations—just pure DevOps wizardry! 🧙‍♂️✨&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Why This Project?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;We set out to create a fully automated deployment pipeline with a few key objectives:&lt;br&gt;
✅ &lt;strong&gt;Automate Deployments&lt;/strong&gt; – Because clicking buttons is overrated.&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Infrastructure as Code (IaC)&lt;/strong&gt; – Terraform makes provisioning as easy as writing poetry.&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Containerization&lt;/strong&gt; – So our app runs smoothly, anywhere, anytime.&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;AWS Deployment&lt;/strong&gt; – Because cloud is king, and EC2 is our throne.  &lt;/p&gt;


&lt;h2&gt;
  
  
  &lt;strong&gt;🛠 Tech Stack &amp;amp; Tools Used&lt;/strong&gt;
&lt;/h2&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Infrastructure &amp;amp; Deployment&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;🔹 &lt;strong&gt;AWS EC2&lt;/strong&gt; → Our app’s luxurious penthouse in the cloud.&lt;br&gt;&lt;br&gt;
🔹 &lt;strong&gt;Terraform&lt;/strong&gt; → Automates infrastructure like a charm.&lt;br&gt;&lt;br&gt;
🔹 &lt;strong&gt;GitHub Actions&lt;/strong&gt; → Our deployment butler, making CI/CD effortless.&lt;br&gt;&lt;br&gt;
🔹 &lt;strong&gt;Docker &amp;amp; Docker Compose&lt;/strong&gt; → Containers keep our app lightweight and portable.&lt;br&gt;&lt;br&gt;
🔹 &lt;strong&gt;SSH (appleboy/ssh-action)&lt;/strong&gt; → Because deploying securely is non-negotiable.  &lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Backend &amp;amp; Database&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;🔹 &lt;strong&gt;Flask&lt;/strong&gt; → Python’s sleek and simple web framework.&lt;br&gt;&lt;br&gt;
🔹 &lt;strong&gt;PostgreSQL&lt;/strong&gt; → The brain storing all our precious data.  &lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Version Control &amp;amp; Registry&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;🔹 &lt;strong&gt;Git &amp;amp; GitHub&lt;/strong&gt; → Our code’s happy place.&lt;br&gt;&lt;br&gt;
🔹 &lt;strong&gt;Docker Hub&lt;/strong&gt; → The treasure chest for our container images.  &lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Security &amp;amp; Networking&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;🔹 &lt;strong&gt;IAM Roles &amp;amp; Policies&lt;/strong&gt; → Guarding AWS like a bouncer at an exclusive club.&lt;br&gt;&lt;br&gt;
🔹 &lt;strong&gt;Security Groups&lt;/strong&gt; → Keeping unwanted traffic out like a medieval fortress.  &lt;/p&gt;


&lt;h2&gt;
  
  
  &lt;strong&gt;📌 Project Setup &amp;amp; Installation Guide&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This guide will walk you through setting up the project from scratch. No magic wands required, just follow these steps! 🧙‍♂️&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;🛠 Prerequisites&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Before you dive in, ensure you have these installed:&lt;/p&gt;

&lt;p&gt;🔹 &lt;strong&gt;On Your Local Machine:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Git&lt;/strong&gt; → Version control is life.&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Docker &amp;amp; Docker Compose&lt;/strong&gt; → Containerization makes life easier.&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Python 3.x &amp;amp; pip&lt;/strong&gt; → Flask won’t run without it.&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Terraform&lt;/strong&gt; → Because writing YAML files is old school.&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;AWS CLI&lt;/strong&gt; → Talking to AWS like a pro.  &lt;/p&gt;

&lt;p&gt;🔹 &lt;strong&gt;On AWS EC2 Instance:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Ubuntu 22.04&lt;/strong&gt; (or latest stable version).&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Docker &amp;amp; Docker Compose installed.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;PostgreSQL installed manually or via Docker.&lt;/strong&gt;  &lt;/p&gt;


&lt;h2&gt;
  
  
  &lt;strong&gt;📂 Cloning the Repositories&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Now let’s grab the code and start the fun!&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;# Clone the main project repo&lt;/span&gt;
git clone https://github.com/DestinyObs/ictg_task.git
&lt;span class="nb"&gt;cd &lt;/span&gt;ictg_task

&lt;span class="c"&gt;# Clone the Terraform automation repo&lt;/span&gt;
git clone https://github.com/DestinyObs/ictg_automate_v2.git
&lt;span class="nb"&gt;cd &lt;/span&gt;ictg_automate_v2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ⚙️ Setting Up Infrastructure on AWS with Terraform
&lt;/h2&gt;

&lt;p&gt;Terraform is our infrastructure wizard, automating EC2 provisioning and security configurations so we don’t have to click around AWS like it’s 2010.&lt;/p&gt;

&lt;h3&gt;
  
  
  🏗️ Provisioning an EC2 Instance with Terraform
&lt;/h3&gt;

&lt;h4&gt;
  
  
  🔹 Steps to Deploy:
&lt;/h4&gt;

&lt;p&gt;1️⃣ Navigate to the Terraform automation repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;cd &lt;/span&gt;ictg_automate_v2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2️⃣ Initialize Terraform:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;3️⃣ Validate the configuration:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;4️⃣ Preview what Terraform is about to create:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;5️⃣ Apply and deploy the infrastructure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   terraform apply &lt;span class="nt"&gt;-auto-approve&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;💡 After execution, Terraform will provide the EC2 instance details like IP address and security settings.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ 1. Infrastructure Setup (Terraform)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🔑 1.1 Generating an SSH Key Pair
&lt;/h3&gt;

&lt;p&gt;Before launching the EC2 instance, we need an SSH key to securely connect to it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"tls_private_key"&lt;/span&gt; &lt;span class="s2"&gt;"ec2_key"&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="s2"&gt;"RSA"&lt;/span&gt;
  &lt;span class="nx"&gt;rsa_bits&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2048&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📌 &lt;strong&gt;Explanation:&lt;/strong&gt;&lt;br&gt;
✅ Generates an RSA 2048-bit private key for SSH authentication. No more passwords—only secure keys!&lt;/p&gt;


&lt;h3&gt;
  
  
  🔑 1.2 Creating a Key Pair in AWS
&lt;/h3&gt;

&lt;p&gt;To allow SSH access, we need to register the public key with AWS.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_key_pair"&lt;/span&gt; &lt;span class="s2"&gt;"ictg_key"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;key_name&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key_name&lt;/span&gt;
  &lt;span class="nx"&gt;public_key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tls_private_key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ec2_key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;public_key_openssh&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📌 &lt;strong&gt;Explanation:&lt;/strong&gt;&lt;br&gt;
✅ This creates an AWS Key Pair using our generated SSH key. &lt;br&gt;
✅ The private key remains local for secure SSH connections.&lt;/p&gt;


&lt;h3&gt;
  
  
  📂 1.3 Storing the Private Key Locally
&lt;/h3&gt;

&lt;p&gt;Terraform saves the private key to a file for authentication.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"local_file"&lt;/span&gt; &lt;span class="s2"&gt;"ssh_key"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;content&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tls_private_key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ec2_key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;private_key_pem&lt;/span&gt;
  &lt;span class="nx"&gt;filename&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"${path.module}/ictg_automate_key.pem"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📌 &lt;strong&gt;Important:&lt;/strong&gt; Keep this key &lt;strong&gt;safe&lt;/strong&gt;—losing it is like losing your house keys, but worse.&lt;/p&gt;




&lt;h3&gt;
  
  
  🔒 1.4 Security Group Configuration
&lt;/h3&gt;

&lt;p&gt;A Security Group defines what network traffic is allowed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_security_group"&lt;/span&gt; &lt;span class="s2"&gt;"ictg_automate_sg"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;security_group_name&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Allow SSH, HTTP, and necessary ports"&lt;/span&gt;

  &lt;span class="nx"&gt;ingress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;
    &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;
    &lt;span class="nx"&gt;protocol&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tcp"&lt;/span&gt;
    &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# Open for SSH (Restrict in production)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;ingress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8000&lt;/span&gt;
    &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8000&lt;/span&gt;
    &lt;span class="nx"&gt;protocol&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tcp"&lt;/span&gt;
    &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# Backend API access&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;ingress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5173&lt;/span&gt;
    &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5173&lt;/span&gt;
    &lt;span class="nx"&gt;protocol&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tcp"&lt;/span&gt;
    &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# Frontend access&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;ingress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5432&lt;/span&gt;
    &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5432&lt;/span&gt;
    &lt;span class="nx"&gt;protocol&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tcp"&lt;/span&gt;
    &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# PostgreSQL database access&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;egress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="nx"&gt;protocol&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"-1"&lt;/span&gt;
    &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# Allow all outbound traffic&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📌 &lt;strong&gt;Explanation:&lt;/strong&gt;&lt;br&gt;
✅ SSH (22) → Remote access.&lt;br&gt;
✅ Backend (8000) → API communication.&lt;br&gt;
✅ Frontend (5173) → Web app access.&lt;br&gt;
✅ Database (5432) → PostgreSQL connectivity.&lt;br&gt;
✅ Outbound rule → Allows all outgoing traffic for smooth operations.&lt;/p&gt;


&lt;h3&gt;
  
  
  💻 1.5 Creating the EC2 Instance
&lt;/h3&gt;

&lt;p&gt;Finally, let’s provision our EC2 instance with Terraform.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_instance"&lt;/span&gt; &lt;span class="s2"&gt;"app_server"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ami&lt;/span&gt;           &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ami_id&lt;/span&gt;
  &lt;span class="nx"&gt;instance_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instance_type&lt;/span&gt;
  &lt;span class="nx"&gt;key_name&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_key_pair&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ictg_key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key_name&lt;/span&gt;
  &lt;span class="nx"&gt;security_groups&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;aws_security_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ictg_automate_sg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="nx"&gt;user_data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"${path.module}/app-setup.sh"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nx"&gt;provisioner&lt;/span&gt; &lt;span class="s2"&gt;"file"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;source&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"app-setup.sh"&lt;/span&gt;
    &lt;span class="nx"&gt;destination&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"/home/ubuntu/app-setup.sh"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;provisioner&lt;/span&gt; &lt;span class="s2"&gt;"remote-exec"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;inline&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="s2"&gt;"chmod +x /home/ubuntu/app-setup.sh"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"sudo /home/ubuntu/app-setup.sh"&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;connection&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ssh"&lt;/span&gt;
    &lt;span class="nx"&gt;user&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ubuntu"&lt;/span&gt;
    &lt;span class="nx"&gt;private_key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tls_private_key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ec2_key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;private_key_pem&lt;/span&gt;
    &lt;span class="nx"&gt;host&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;public_ip&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ICTG App Server"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📌 &lt;strong&gt;Explanation:&lt;/strong&gt;&lt;br&gt;
✅ Uses an Ubuntu AMI (adjust as needed).&lt;br&gt;
✅ Attaches the Security Group.&lt;br&gt;
✅ Uploads and executes a setup script (&lt;code&gt;app-setup.sh&lt;/code&gt;).&lt;br&gt;
✅ Establishes an SSH connection.&lt;/p&gt;


&lt;h3&gt;
  
  
  📍 1.6 Outputting Important Details
&lt;/h3&gt;

&lt;p&gt;Terraform outputs key details so you don’t have to dig around AWS.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"instance_public_ip"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Public IP of the EC2 instance"&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;app_server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;public_ip&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"private_key_file"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Path to the private key file"&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local_file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ssh_key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filename&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"security_group_id"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ID of the created security group"&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_security_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ictg_automate_sg&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📌 &lt;strong&gt;Explanation:&lt;/strong&gt;&lt;br&gt;
✅ Public IP → Needed to access the server.&lt;br&gt;
✅ Private Key File → Used for SSH login.&lt;br&gt;
✅ Security Group ID → For managing network rules.&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%2F1p88jthty8b96lih80bf.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%2F1p88jthty8b96lih80bf.png" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🚀 &lt;strong&gt;Next Steps:&lt;/strong&gt; Now that our infrastructure is live, let’s move on to containerizing the application with Docker! 🐳&lt;/p&gt;
&lt;h2&gt;
  
  
  🐳 2. Containerizing the Application (Docker Setup)
&lt;/h2&gt;

&lt;p&gt;The application is containerized using Docker for consistency and portability.&lt;/p&gt;

&lt;p&gt;🔹 Steps to Build and Run Locally:&lt;/p&gt;

&lt;p&gt;1️⃣ Navigate to the project directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;ictg_task
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2️⃣ Build and start the containers using Docker Compose:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose up &lt;span class="nt"&gt;--build&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;3️⃣ Verify that the containers are running:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;🔹 Docker Compose Configuration&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="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.8"&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./backend&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend_service&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8000:8000"&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;database&lt;/span&gt;
    &lt;span class="na"&gt;env_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./backend/.env&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;devops-network&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;

  &lt;span class="na"&gt;frontend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./frontend&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;frontend_service&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5173:5173"&lt;/span&gt;
    &lt;span class="na"&gt;env_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./frontend/.env&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;devops-network&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;

  &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres_database&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5432:5432"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./postgres_data:/var/lib/postgresql/data&lt;/span&gt;
    &lt;span class="na"&gt;env_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./backend/.env&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;devops-network&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;devops-network&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bridge&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📌 Explanation:&lt;br&gt;
✅ Backend (Flask API) → Runs on port 8000.&lt;br&gt;
✅ Frontend (React/Vue) → Runs on port 5173.&lt;br&gt;
✅ Database (PostgreSQL) → Runs on port 5432.&lt;br&gt;
✅ Uses Environment Variables from .env files.&lt;br&gt;
✅ Ensures services restart if they fail (restart: unless-stopped).&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%2Fdbec6icq7z4ztszgbm76.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%2Fdbec6icq7z4ztszgbm76.png" alt="Image description" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🚀 3. Deploying the Application to EC2&lt;/p&gt;

&lt;p&gt;Once Terraform provisions the EC2 instance, GitHub Actions will handle automatic deployment.&lt;/p&gt;

&lt;p&gt;🔹 Manual Deployment via SSH (Optional Alternative to CI/CD)&lt;/p&gt;

&lt;p&gt;If needed, you can manually deploy using SSH:&lt;br&gt;
1️⃣ SSH into the EC2 instance:&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; your-key.pem ubuntu@&amp;lt;EC2_PUBLIC_IP&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2️⃣ Pull the latest Docker images from Docker Hub:&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="s"&gt;docker pull destinyobs/ictg_task-backend:latest&lt;/span&gt;
&lt;span class="s"&gt;docker pull destinyobs/ictg_task-frontend:latest&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;3️⃣ Run the application using Docker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🎯 4. Verifying the Deployment&lt;/p&gt;

&lt;p&gt;Once deployed, test the setup:&lt;br&gt;
✅ Backend:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; GET http://&amp;lt;EC2_PUBLIC_IP&amp;gt;:8000/health
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected Response: { "status": "ok" }&lt;/p&gt;

&lt;p&gt;✅ Frontend: Open http://:5173 in a browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  🪔 3. CI/CD Pipeline Setup for EC2 Deployment Using GitHub Actions
&lt;/h2&gt;

&lt;p&gt;To streamline the deployment process of our application to an AWS EC2 instance, we leverage &lt;strong&gt;GitHub Actions&lt;/strong&gt;. This setup ensures that every push to the &lt;code&gt;main&lt;/code&gt; branch triggers an automated build and deployment of our backend and frontend applications.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Workflow Overview&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This GitHub Actions workflow:&lt;br&gt;
✅ Triggers on every push to the &lt;code&gt;main&lt;/code&gt; branch.&lt;br&gt;
✅ Builds Docker images for the frontend and backend.&lt;br&gt;
✅ Pushes the images to &lt;strong&gt;Docker Hub&lt;/strong&gt;.&lt;br&gt;
✅ Connects to the &lt;strong&gt;EC2 instance&lt;/strong&gt; via SSH.&lt;br&gt;
✅ Deploys the updated containers automatically.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Workflow Breakdown&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Define the Workflow&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to EC2&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This triggers the workflow when a push occurs on the &lt;code&gt;main&lt;/code&gt; branch.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. Define the Deployment Job&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Defines a job called &lt;code&gt;deploy&lt;/code&gt; that runs on an Ubuntu-based GitHub Actions runner.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3. Checkout the Repository&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;steps&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;Checkout Repository&lt;/span&gt;
    &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fetches the repository code for further processing.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;4. Authenticate with Docker Hub&lt;/strong&gt;
&lt;/h3&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;Log in to Docker Hub&lt;/span&gt;
    &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker/login-action@v2&lt;/span&gt;
    &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.DOCKER_USERNAME }}&lt;/span&gt;
      &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.DOCKER_PASSWORD }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Logs into Docker Hub securely using GitHub Secrets.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;5. Build and Push Docker Images&lt;/strong&gt;
&lt;/h3&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;Build and Push Backend Image&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;docker build -t ${{ secrets.DOCKER_USERNAME }}/ictg_task-backend:latest ./backend&lt;/span&gt;
      &lt;span class="s"&gt;docker push ${{ secrets.DOCKER_USERNAME }}/ictg_task-backend:latest&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;Build and Push Frontend Image&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;docker build -t ${{ secrets.DOCKER_USERNAME }}/ictg_task-frontend:latest ./frontend&lt;/span&gt;
      &lt;span class="s"&gt;docker push ${{ secrets.DOCKER_USERNAME }}/ictg_task-frontend:latest&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Builds and pushes Docker images for both the backend and frontend.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;6. Connect to EC2 and Deploy Containers&lt;/strong&gt;
&lt;/h3&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 to EC2&lt;/span&gt;
    &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;appleboy/ssh-action@v0.1.10&lt;/span&gt;
    &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.EC2_HOST }}&lt;/span&gt;
      &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.EC2_USER }}&lt;/span&gt;
      &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.EC2_PRIVATE_KEY }}&lt;/span&gt;
      &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Securely connects to the EC2 instance using SSH.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;7. Remove Old Containers&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;        &lt;span class="s"&gt;docker stop backend_service frontend_service postgres_database || &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="s"&gt;docker rm backend_service frontend_service postgres_database || &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Stops and removes any existing containers to prevent conflicts.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;8. Pull the Latest Docker Images&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;        &lt;span class="s"&gt;docker pull ${{ secrets.DOCKER_USERNAME }}/ictg_task-backend:latest&lt;/span&gt;
        &lt;span class="s"&gt;docker pull ${{ secrets.DOCKER_USERNAME }}/ictg_task-frontend:latest&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Retrieves the latest versions of the images from Docker Hub.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;9. Ensure Docker Network Exists&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;        &lt;span class="s"&gt;docker network inspect devops-network &amp;gt;/dev/null 2&amp;gt;&amp;amp;1 || docker network create devops-network&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Checks for the network and creates it if missing.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;10. Run PostgreSQL Container&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;        &lt;span class="s"&gt;docker run -d \&lt;/span&gt;
          &lt;span class="s"&gt;--name postgres_database \&lt;/span&gt;
          &lt;span class="s"&gt;--network devops-network \&lt;/span&gt;
          &lt;span class="s"&gt;-e POSTGRES_USER=app \&lt;/span&gt;
          &lt;span class="s"&gt;-e POSTGRES_PASSWORD=${{ secrets.POSTGRES_PASSWORD }} \&lt;/span&gt;
          &lt;span class="s"&gt;-e POSTGRES_DB=ictg_db \&lt;/span&gt;
          &lt;span class="s"&gt;-p 5432:5432 \&lt;/span&gt;
          &lt;span class="s"&gt;--restart unless-stopped \&lt;/span&gt;
          &lt;span class="s"&gt;postgres:latest&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ensures the database container runs with the correct configurations.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;11. Ensure PostgreSQL Readiness&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;        &lt;span class="s"&gt;retries=10&lt;/span&gt;
        &lt;span class="s"&gt;until docker exec postgres_database pg_isready -U app || [ $retries -eq 0 ]; do&lt;/span&gt;
          &lt;span class="s"&gt;echo "Waiting for PostgreSQL to be ready..."&lt;/span&gt;
          &lt;span class="s"&gt;sleep &lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;
          &lt;span class="s"&gt;retries=$((retries - 1))&lt;/span&gt;
        &lt;span class="s"&gt;done&lt;/span&gt;
        &lt;span class="s"&gt;if [ $retries -eq 0 ]; then&lt;/span&gt;
          &lt;span class="s"&gt;echo "PostgreSQL failed to start." &amp;gt;&amp;amp;2&lt;/span&gt;
          &lt;span class="s"&gt;exit &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
        &lt;span class="s"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Waits for PostgreSQL to be fully initialized.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;12. Run Backend and Frontend Services&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;        &lt;span class="s"&gt;docker run -d \&lt;/span&gt;
          &lt;span class="s"&gt;--name backend_service \&lt;/span&gt;
          &lt;span class="s"&gt;--network devops-network \&lt;/span&gt;
          &lt;span class="s"&gt;-e DATABASE_URL="postgresql://app:${{ secrets.POSTGRES_PASSWORD }}@postgres_database:5432/ictg_db" \&lt;/span&gt;
          &lt;span class="s"&gt;-p 8000:8000 \&lt;/span&gt;
          &lt;span class="s"&gt;--restart unless-stopped \&lt;/span&gt;
          &lt;span class="s"&gt;${{ secrets.DOCKER_USERNAME }}/ictg_task-backend:latest&lt;/span&gt;

        &lt;span class="s"&gt;docker run -d \&lt;/span&gt;
          &lt;span class="s"&gt;--name frontend_service \&lt;/span&gt;
          &lt;span class="s"&gt;--network devops-network \&lt;/span&gt;
          &lt;span class="s"&gt;-p 5173:5173 \&lt;/span&gt;
          &lt;span class="s"&gt;--restart unless-stopped \&lt;/span&gt;
          &lt;span class="s"&gt;${{ secrets.DOCKER_USERNAME }}/ictg_task-frontend:latest&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deploys the backend and frontend services.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;13. Clean Up Unused Docker Resources&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;        &lt;span class="s"&gt;docker system prune -af&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Frees up disk space by removing unused containers and images.&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%2F4hwmm6sdrqtzsryaar1e.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%2F4hwmm6sdrqtzsryaar1e.png" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&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%2Fix1uv87dhc3coy048rm1.png" alt="Image description" width="800" height="450"&gt;
&lt;/h2&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Security Considerations&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;✅ &lt;strong&gt;Secrets Management:&lt;/strong&gt; All sensitive credentials are stored securely in GitHub Secrets.&lt;br&gt;
✅ &lt;strong&gt;Access Restrictions:&lt;/strong&gt; The EC2 Security Group is configured to allow only necessary traffic.&lt;/p&gt;

&lt;h2&gt;
  
  
  ✅ &lt;strong&gt;Database Security:&lt;/strong&gt; PostgreSQL password is stored securely and not hardcoded.
&lt;/h2&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Why This Setup?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;✅ &lt;strong&gt;Fully Automated Deployment&lt;/strong&gt; – Code push triggers deployment.&lt;br&gt;
✅ &lt;strong&gt;Zero Downtime&lt;/strong&gt; – Smooth updates without disruptions.&lt;br&gt;
✅ &lt;strong&gt;Security First&lt;/strong&gt; – No hardcoded credentials.&lt;br&gt;
✅ &lt;strong&gt;Efficient Resource Management&lt;/strong&gt; – Cleanup ensures optimal performance.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion &amp;amp; Next Steps&lt;/strong&gt;
&lt;/h2&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Summary of Achievements&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;We successfully automated the deployment of a full-stack application using &lt;strong&gt;Terraform, Docker, and GitHub Actions&lt;/strong&gt;. The key milestones included:&lt;/p&gt;

&lt;p&gt;🔹 &lt;strong&gt;Infrastructure Setup&lt;/strong&gt; – Provisioned an AWS EC2 instance using Terraform.&lt;br&gt;
🔹 &lt;strong&gt;Containerization&lt;/strong&gt; – Dockerized backend, frontend, and database services.&lt;br&gt;
🔹 &lt;strong&gt;CI/CD Pipeline&lt;/strong&gt; – Automated build and deployment using GitHub Actions.&lt;br&gt;
🔹 &lt;strong&gt;Automated Deployment&lt;/strong&gt; – Utilized SSH actions to update containers smoothly.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Potential Improvements&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;🚀 &lt;strong&gt;Enhanced Security:&lt;/strong&gt; Implement IAM roles, security best practices, and database access restrictions.&lt;br&gt;
🚀 &lt;strong&gt;Automated Scaling:&lt;/strong&gt; Leverage AWS Auto Scaling and Load Balancing.&lt;br&gt;
🚀 &lt;strong&gt;Monitoring &amp;amp; Logging:&lt;/strong&gt; Integrate Prometheus, Grafana, and centralized logging.&lt;br&gt;
🚀 &lt;strong&gt;Infrastructure as Code Refinement:&lt;/strong&gt; Use remote state management (S3) and modularized configurations.&lt;br&gt;
🚀 &lt;strong&gt;Nginx Reverse Proxy &amp;amp; SSL:&lt;/strong&gt; Implement Nginx for traffic management and SSL security.&lt;/p&gt;

&lt;p&gt;This project provides a strong foundation for continuous deployment and scaling in a &lt;strong&gt;DevOps-oriented environment&lt;/strong&gt;. 🚀&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This setup is a foundational approach as I continue expanding my expertise in this field. I hope this guide proves useful to fellow DevOps enthusiasts tackling similar challenges!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Maintenance Script: Keeping Your Linux Box in Check</title>
      <dc:creator>Destiny Obs</dc:creator>
      <pubDate>Thu, 27 Mar 2025 10:56:30 +0000</pubDate>
      <link>https://dev.to/destinyobs/maintenance-script-keeping-your-linux-box-in-check-4chh</link>
      <guid>https://dev.to/destinyobs/maintenance-script-keeping-your-linux-box-in-check-4chh</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Welcome, esteemed engineer, noble sysadmin, or brave soul who just realized their server is on fire. 🎩🔥&lt;/p&gt;

&lt;p&gt;System maintenance is like brushing your teeth—you can skip it, but eventually, it’ll cost you. This script is your trusty sidekick, automating crucial tasks like monitoring CPU and disk usage, restarting critical services, and applying security updates. Think of it as a tiny, relentless janitor for your Linux system, sweeping up messes before they turn into disasters.&lt;/p&gt;

&lt;p&gt;This guide will walk you through the script’s functions, ensuring that you understand what each piece does instead of just running it blindly and praying to the Bash gods.&lt;/p&gt;

&lt;p&gt;And no, this knowledge is NOT a waste—whether you’re a rookie or a battle-hardened sysadmin, mastering these skills will make you the unsung hero of your team.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Is This Important?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Monitoring Resource Usage
&lt;/h3&gt;

&lt;p&gt;Ever had a server slow down so badly you suspected it had just given up on life? Monitoring CPU, RAM, and disk usage helps you spot trouble before your users start screaming on Twitter.&lt;/p&gt;

&lt;p&gt;This script logs system metrics and warns you when things start going south.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Detecting Security Threats
&lt;/h3&gt;

&lt;p&gt;Hackers never sleep, and your logs are proof. SSH brute-force attacks happen all the time, and failed logins pile up like rejection emails from that dream job you applied for.&lt;/p&gt;

&lt;p&gt;This script helps you keep an eye on unauthorized access attempts and system errors.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Ensuring Critical Services Stay Running
&lt;/h3&gt;

&lt;p&gt;Imagine waking up to find out your database crashed hours ago, and now your boss is calling. 😱&lt;/p&gt;

&lt;p&gt;The script monitors essential services (e.g., Nginx, MySQL) and restarts them if they go down—because humans need sleep, but servers don’t.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Automating System Cleanup &amp;amp; Updates
&lt;/h3&gt;

&lt;p&gt;Old temp files waste space. Security patches are life-saving. This script takes care of both, so you don’t have to do it manually like some medieval peasant.&lt;/p&gt;




&lt;h2&gt;
  
  
  Deep Dive Into the Code
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Setting Up Logging
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;LOG_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"./logs"&lt;/span&gt;
&lt;span class="nv"&gt;LOG_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LOG_DIR&lt;/span&gt;&lt;span class="s2"&gt;/system_maintenance.log"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All script actions are recorded in a custom logging directory to avoid system-level permission issues. This ensures the logs are accessible without requiring elevated privileges.&lt;/p&gt;

&lt;p&gt;Additionally, the script ensures the log directory exists:&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;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;-d&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LOG_DIR&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;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LOG_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Placeholder Log Files
&lt;/h3&gt;

&lt;p&gt;The script creates placeholders for missing log files (&lt;code&gt;auth.log&lt;/code&gt; and &lt;code&gt;syslog&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;AUTH_LOG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"./auth.log"&lt;/span&gt;
&lt;span class="nv"&gt;SYS_LOG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"./syslog"&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;$AUTH_LOG&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;touch&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$AUTH_LOG&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    log &lt;span class="s2"&gt;"ℹ️ Created placeholder for auth.log."&lt;/span&gt;
&lt;span class="k"&gt;fi

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;$SYS_LOG&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;touch&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SYS_LOG&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    log &lt;span class="s2"&gt;"ℹ️ Created placeholder for syslog."&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This step eliminates execution errors caused by non-existent files.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Defining Important Variables
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;TEMP_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/tmp"&lt;/span&gt;
&lt;span class="nv"&gt;CRITICAL_SERVICES&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="s2"&gt;"nginx"&lt;/span&gt; &lt;span class="s2"&gt;"mysql"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;DISK_THRESHOLD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;80
&lt;span class="nv"&gt;CPU_THRESHOLD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;75
&lt;span class="nv"&gt;MEM_THRESHOLD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;75
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;TEMP_DIR&lt;/strong&gt;: Temporary files older than 7 days are deleted.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CRITICAL_SERVICES&lt;/strong&gt;: Defines services critical to your environment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Thresholds&lt;/strong&gt;: Sets alarm limits for resource usage.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Logging Function
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;log&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="s1"&gt;'+%Y-%m-%d %H:%M:%S'&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="nb"&gt;tee&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LOG_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Messages are logged with timestamps for easy troubleshooting.&lt;/p&gt;

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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;CPU_USAGE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;top &lt;span class="nt"&gt;-bn1&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"Cpu(s)"&lt;/span&gt; | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'{print $2 + $4}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;MEM_USAGE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;free | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'/Mem/{printf("%.2f"), $3/$2 * 100}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;DISK_USAGE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;df&lt;/span&gt; / | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'NR==2 {print $5}'&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s1"&gt;'s/%//'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Extracts CPU, memory, and disk usage.&lt;/li&gt;
&lt;li&gt;Checks resource levels against thresholds:
&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="k"&gt;if&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;$CPU_USAGE&lt;/span&gt;&lt;span class="s2"&gt; &amp;gt; &lt;/span&gt;&lt;span class="nv"&gt;$CPU_THRESHOLD&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | bc &lt;span class="nt"&gt;-l&lt;/span&gt;&lt;span class="si"&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;log &lt;span class="s2"&gt;"⚠️ High CPU Usage detected: &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CPU_USAGE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;%"&lt;/span&gt;
  &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Warnings are raised if limits are exceeded.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Analyzing Logs for Security &amp;amp; Errors
&lt;/h3&gt;

&lt;p&gt;The script analyzes failed SSH login attempts and system errors:&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;FAILED_LOGINS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"Failed password"&lt;/span&gt; ./auth.log | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;SYSTEM_ERRORS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"error"&lt;/span&gt; ./syslog | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$FAILED_LOGINS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-gt&lt;/span&gt; 5 &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 &lt;span class="s2"&gt;"🚨 Multiple failed SSH login attempts detected!"&lt;/span&gt;
&lt;span class="k"&gt;fi

if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SYSTEM_ERRORS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-gt&lt;/span&gt; 10 &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 &lt;span class="s2"&gt;"⚠️ High number of system errors detected!"&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures you stay informed of potential security risks or system instability.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Cleaning Up Temporary Files
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;find &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TEMP_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-type&lt;/span&gt; f &lt;span class="nt"&gt;-atime&lt;/span&gt; +7 &lt;span class="nt"&gt;-delete&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Old temporary files are cleared to improve system performance.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Restarting Critical Services
&lt;/h3&gt;

&lt;p&gt;The script checks critical services and restarts them if they are not running:&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;service &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;CRITICAL_SERVICES&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
    if &lt;/span&gt;systemctl is-active &lt;span class="nt"&gt;--quiet&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$service&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;log &lt;span class="s2"&gt;"✅ &lt;/span&gt;&lt;span class="nv"&gt;$service&lt;/span&gt;&lt;span class="s2"&gt; is running."&lt;/span&gt;
    &lt;span class="k"&gt;else
        &lt;/span&gt;log &lt;span class="s2"&gt;"⚠️ &lt;/span&gt;&lt;span class="nv"&gt;$service&lt;/span&gt;&lt;span class="s2"&gt; is not running. Restarting..."&lt;/span&gt;
        systemctl restart &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$service&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;systemctl is-active &lt;span class="nt"&gt;--quiet&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$service&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
            &lt;/span&gt;log &lt;span class="s2"&gt;"🔄 Successfully restarted &lt;/span&gt;&lt;span class="nv"&gt;$service&lt;/span&gt;&lt;span class="s2"&gt;."&lt;/span&gt;
        &lt;span class="k"&gt;else
            &lt;/span&gt;log &lt;span class="s2"&gt;"❌ Failed to restart &lt;/span&gt;&lt;span class="nv"&gt;$service&lt;/span&gt;&lt;span class="s2"&gt;!"&lt;/span&gt;
        &lt;span class="k"&gt;fi
    fi
done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  9. Applying System Updates
&lt;/h3&gt;

&lt;p&gt;To avoid permission issues, the script checks for elevated privileges before attempting updates:&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;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$EUID&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-ne&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 &lt;span class="s2"&gt;"⚠️ System updates require elevated permissions. Please run the script with sudo."&lt;/span&gt;
    &lt;span class="k"&gt;return
fi

&lt;/span&gt;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt upgrade &lt;span class="nt"&gt;-y&lt;/span&gt;

&lt;span class="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 &lt;span class="s2"&gt;"✅ System updates completed successfully."&lt;/span&gt;
&lt;span class="k"&gt;else
    &lt;/span&gt;log &lt;span class="s2"&gt;"❌ System updates failed! Check the logs for details."&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures you know when and how to address missing updates.&lt;/p&gt;

&lt;h3&gt;
  
  
  10. Running Everything in Sequence
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;main&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    log &lt;span class="s2"&gt;"===== System Maintenance Script Started ====="&lt;/span&gt;
    monitor_system
    analyze_logs
    optimize_performance
    apply_updates
    log &lt;span class="s2"&gt;"===== System Maintenance Script Completed ====="&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The script smoothly executes all steps, keeping your system maintained with minimal intervention.&lt;/p&gt;




&lt;h2&gt;
  
  
  Automating with Cron
&lt;/h2&gt;

&lt;p&gt;To schedule the script daily at midnight:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;0 0 &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; /path/to/script.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paste this into &lt;code&gt;crontab&lt;/code&gt; via &lt;code&gt;crontab -e&lt;/code&gt; for automatic maintenance tasks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ensure the script has execution permissions (&lt;code&gt;chmod +x script.sh&lt;/code&gt;) and is run with &lt;code&gt;sudo&lt;/code&gt; to function correctly.
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;This script is just one of many ways to automate system maintenance. It’s a simple yet effective tool to help you monitor and manage your system natively. More advanced methods exist, but this provides a solid foundation for understanding how things work under the hood.&lt;/p&gt;

&lt;p&gt;Happy automating! 🛠️🚀&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I’m DestinyObs | iBuild | iDeploy | iSecure | iSustain&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Automating AWS S3 Bucket Setup with Bash and PowerShell</title>
      <dc:creator>Destiny Obs</dc:creator>
      <pubDate>Thu, 27 Mar 2025 10:27:15 +0000</pubDate>
      <link>https://dev.to/destinyobs/automating-aws-s3-bucket-setup-with-bash-and-powershell-3om8</link>
      <guid>https://dev.to/destinyobs/automating-aws-s3-bucket-setup-with-bash-and-powershell-3om8</guid>
      <description>&lt;p&gt;Managing AWS S3 buckets manually is fine—until it isn't. If you've ever found yourself clicking around the AWS Console or typing out endless CLI commands just to set up a simple S3 bucket, then this automation script is for you. With Bash and PowerShell, we’ll make the process seamless, efficient, and (most importantly) repeatable.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 What This Script Does
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Checks for AWS CLI:&lt;/strong&gt; If AWS CLI isn’t installed, it installs it and configures credentials.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Creates an S3 Bucket:&lt;/strong&gt; Takes user input for bucket name and sets it up in a secure manner.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secures the Bucket:&lt;/strong&gt; Ensures no public access is allowed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Uploads a File:&lt;/strong&gt; Lets the user upload a file from their local machine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generates a Pre-signed URL:&lt;/strong&gt; Creates a time-limited download link for the uploaded file.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🏗️ The Bash Script (Linux/macOS)
&lt;/h2&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 check if AWS CLI is installed and install it if necessary&lt;/span&gt;
check_aws_cli&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;# Check if the 'aws' command is available in the system&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nb"&gt;command&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; aws &amp;amp;&amp;gt; /dev/null&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;"AWS CLI not found. Installing AWS CLI..."&lt;/span&gt;

        &lt;span class="c"&gt;# Download the AWS CLI installation package&lt;/span&gt;
        curl &lt;span class="s2"&gt;"https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip"&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s2"&gt;"awscliv2.zip"&lt;/span&gt;

        &lt;span class="c"&gt;# Unzip the downloaded file&lt;/span&gt;
        unzip awscliv2.zip

        &lt;span class="c"&gt;# Install AWS CLI using sudo privileges&lt;/span&gt;
        &lt;span class="nb"&gt;sudo&lt;/span&gt; ./aws/install

        &lt;span class="c"&gt;# Clean up by removing unnecessary installation files&lt;/span&gt;
        &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; aws awscliv2.zip

        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"AWS CLI installed successfully."&lt;/span&gt;
    &lt;span class="k"&gt;else
        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"AWS CLI is already installed."&lt;/span&gt;
    &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# Function to configure AWS CLI with user-provided credentials&lt;/span&gt;
configure_aws&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;"Configuring AWS CLI..."&lt;/span&gt;
    &lt;span class="c"&gt;# Run the interactive AWS CLI configuration command&lt;/span&gt;
    aws configure
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# Function to create an S3 bucket securely&lt;/span&gt;
create_s3_bucket&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;bucket_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;  &lt;span class="c"&gt;# First argument: Name of the S3 bucket&lt;/span&gt;
    &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;region&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;       &lt;span class="c"&gt;# Second argument: AWS region&lt;/span&gt;

    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Creating S3 bucket: &lt;/span&gt;&lt;span class="nv"&gt;$bucket_name&lt;/span&gt;&lt;span class="s2"&gt; in region: &lt;/span&gt;&lt;span class="nv"&gt;$region&lt;/span&gt;&lt;span class="s2"&gt;..."&lt;/span&gt;
    &lt;span class="c"&gt;# Create an S3 bucket using AWS CLI&lt;/span&gt;
    aws s3api create-bucket &lt;span class="nt"&gt;--bucket&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$bucket_name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--region&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$region&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

    &lt;span class="c"&gt;# Check if the bucket creation was successful&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;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Bucket created successfully: &lt;/span&gt;&lt;span class="nv"&gt;$bucket_name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;else
        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Failed to create bucket."&lt;/span&gt;
        &lt;span class="nb"&gt;exit &lt;/span&gt;1  &lt;span class="c"&gt;# Exit script if bucket creation fails&lt;/span&gt;
    &lt;span class="k"&gt;fi&lt;/span&gt;

    &lt;span class="c"&gt;# Apply security settings to block public access to the bucket&lt;/span&gt;
    aws s3api put-public-access-block &lt;span class="nt"&gt;--bucket&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$bucket_name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;--public-access-block-configuration&lt;/span&gt; &lt;span class="nv"&gt;BlockPublicAcls&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;,IgnorePublicAcls&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;,BlockPublicPolicy&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;,RestrictPublicBuckets&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true

    echo&lt;/span&gt; &lt;span class="s2"&gt;"Bucket secured: Public access blocked."&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# Function to upload a file to an S3 bucket&lt;/span&gt;
upload_file&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;file_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;    &lt;span class="c"&gt;# First argument: Path to the file to be uploaded&lt;/span&gt;
    &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;bucket_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;  &lt;span class="c"&gt;# Second argument: S3 bucket name&lt;/span&gt;

    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Uploading file: &lt;/span&gt;&lt;span class="nv"&gt;$file_path&lt;/span&gt;&lt;span class="s2"&gt; to S3 bucket: &lt;/span&gt;&lt;span class="nv"&gt;$bucket_name&lt;/span&gt;&lt;span class="s2"&gt;..."&lt;/span&gt;
    &lt;span class="c"&gt;# Use AWS CLI to copy the file to the specified S3 bucket&lt;/span&gt;
    aws s3 &lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file_path&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"s3://&lt;/span&gt;&lt;span class="nv"&gt;$bucket_name&lt;/span&gt;&lt;span class="s2"&gt;/"&lt;/span&gt;

    &lt;span class="c"&gt;# Check if the upload was successful&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;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"File uploaded successfully."&lt;/span&gt;
    &lt;span class="k"&gt;else
        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"File upload failed."&lt;/span&gt;
        &lt;span class="nb"&gt;exit &lt;/span&gt;1  &lt;span class="c"&gt;# Exit script if upload fails&lt;/span&gt;
    &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# Function to generate a pre-signed URL for an S3 object (file)&lt;/span&gt;
generate_presigned_url&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;bucket_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;  &lt;span class="c"&gt;# First argument: S3 bucket name&lt;/span&gt;
    &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;file_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;    &lt;span class="c"&gt;# Second argument: Name of the file in the bucket&lt;/span&gt;
    &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;expiry&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;# Third argument: Expiry time in seconds for the URL&lt;/span&gt;

    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Generating pre-signed URL..."&lt;/span&gt;
    &lt;span class="c"&gt;# Generate a pre-signed URL that allows temporary access to the file&lt;/span&gt;
    &lt;span class="nv"&gt;presigned_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;aws s3 presign &lt;span class="s2"&gt;"s3://&lt;/span&gt;&lt;span class="nv"&gt;$bucket_name&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;$file_name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--expires-in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$expiry&lt;/span&gt;&lt;span class="s2"&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;"Pre-signed URL (valid for &lt;/span&gt;&lt;span class="nv"&gt;$expiry&lt;/span&gt;&lt;span class="s2"&gt; seconds):"&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;$presigned_url&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# Main script execution begins here&lt;/span&gt;

&lt;span class="c"&gt;# Step 1: Ensure AWS CLI is installed&lt;/span&gt;
check_aws_cli

&lt;span class="c"&gt;# Step 2: Configure AWS CLI with user credentials&lt;/span&gt;
configure_aws

&lt;span class="c"&gt;# Step 3: Prompt the user for S3 bucket details&lt;/span&gt;
&lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"Enter S3 bucket name: "&lt;/span&gt; bucket_name  &lt;span class="c"&gt;# Get bucket name from user&lt;/span&gt;
&lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"Enter AWS region (e.g., us-east-1): "&lt;/span&gt; region  &lt;span class="c"&gt;# Get AWS region from user&lt;/span&gt;

&lt;span class="c"&gt;# Step 4: Create the S3 bucket securely&lt;/span&gt;
create_s3_bucket &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$bucket_name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$region&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# Step 5: Prompt the user for the file to upload&lt;/span&gt;
&lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"Enter file path to upload: "&lt;/span&gt; file_path  &lt;span class="c"&gt;# Get file path from user&lt;/span&gt;

&lt;span class="c"&gt;# Step 6: Upload the specified file to the created S3 bucket&lt;/span&gt;
upload_file &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file_path&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$bucket_name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# Step 7: Extract file name from file path&lt;/span&gt;
&lt;span class="nv"&gt;file_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;basename&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file_path&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Step 8: Generate a pre-signed URL valid for 1 hour (3600 seconds)&lt;/span&gt;
generate_presigned_url &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$bucket_name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file_name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; 3600

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  🛠️ Breakdown
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Checking for AWS CLI&lt;/strong&gt;: If it's missing, the script downloads and installs it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configuring AWS CLI&lt;/strong&gt;: It prompts the user to enter AWS credentials.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bucket Creation&lt;/strong&gt;: Ensures a unique bucket is created.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security Setup&lt;/strong&gt;: Disables public access to prevent unwanted exposure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Uploading Files&lt;/strong&gt;: User can specify a file to upload.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generating Pre-signed URL&lt;/strong&gt;: Provides a temporary download link for file sharing.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  📚 How to Save and Run the Script
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Saving the Script&lt;/strong&gt;
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Open a terminal and navigate to your desired directory.&lt;/li&gt;
&lt;li&gt;Create a new script file:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   nano s3_script.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Copy and paste the script content into the file.&lt;/li&gt;
&lt;li&gt;Save and exit (Press &lt;code&gt;CTRL + X&lt;/code&gt;, then &lt;code&gt;Y&lt;/code&gt;, and hit &lt;code&gt;Enter&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Running the Script&lt;/strong&gt;
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Grant execute permission:
&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="nb"&gt;chmod&lt;/span&gt; +x s3_script.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Run the script:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   ./s3_script.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Follow the on-screen prompts to configure AWS CLI, create a bucket, upload a file, and generate a pre-signed URL.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  🖥️ The PowerShell Script (Windows)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check if AWS CLI is installed&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Get-Command&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ErrorAction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SilentlyContinue&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Write-Output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AWS CLI not found! Installing..."&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Invoke-WebRequest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Uri&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://awscli.amazonaws.com/AWSCLIV2.msi"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-OutFile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AWSCLIV2.msi"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Start-Process&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;msiexec.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ArgumentList&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/i AWSCLIV2.msi /quiet"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Wait&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Remove-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AWSCLIV2.msi"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;Write-Output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Configuring AWS CLI..."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Start-Process&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ArgumentList&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"configure"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-NoNewWindow&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Wait&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Get user input for bucket name&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$BucketName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Read-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Enter a unique S3 bucket name"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Create S3 Bucket&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;aws&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s3api&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;create-bucket&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--bucket&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$BucketName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--region&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;us-east-1&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;Write-Output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Blocking public access..."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;aws&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s3api&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;put-public-access-block&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--bucket&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$BucketName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--public-access-block-configuration&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;BlockPublicAcls&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;IgnorePublicAcls&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;BlockPublicPolicy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;RestrictPublicBuckets&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Upload a file&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$FilePath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Read-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Enter the file path to upload"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;aws&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$FilePath&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s3://&lt;/span&gt;&lt;span class="nv"&gt;$BucketName&lt;/span&gt;&lt;span class="nx"&gt;/&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Generate pre-signed URL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$FileName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Split-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$FilePath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Leaf&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$PresignedUrl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;aws&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;presign&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"s3://&lt;/span&gt;&lt;span class="nv"&gt;$BucketName&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="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--expires-in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;3600&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;Write-Output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Your pre-signed URL: &lt;/span&gt;&lt;span class="nv"&gt;$PresignedUrl&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🔍 Breakdown
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Checks and installs AWS CLI if missing.&lt;/li&gt;
&lt;li&gt;Configures AWS credentials.&lt;/li&gt;
&lt;li&gt;Creates a bucket and secures it.&lt;/li&gt;
&lt;li&gt;Uploads a user-specified file.&lt;/li&gt;
&lt;li&gt;Generates a pre-signed URL for sharing.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  📚 How to Save and Run the Script
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Saving the Script&lt;/strong&gt;
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Open a terminal and navigate to your desired directory.&lt;/li&gt;
&lt;li&gt;Create a new script file:
&lt;code&gt;s3_script.ps1&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Copy and paste the script content into the file.&lt;/li&gt;
&lt;li&gt;Save and exit (Press &lt;code&gt;CTRL + X&lt;/code&gt;, then &lt;code&gt;Y&lt;/code&gt;, and hit &lt;code&gt;Enter&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Running the Script&lt;/strong&gt;
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Grant execute permission:
Allow script execution (if restricted): &lt;code&gt;Set-ExecutionPolicy RemoteSigned -Scope CurrentUser&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Run the script:
&lt;code&gt;.\s3_script.ps1&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Follow the on-screen prompts to configure AWS CLI, create a bucket, upload a file, and generate a pre-signed URL.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🏆 Final Thoughts
&lt;/h2&gt;

&lt;p&gt;With these scripts, setting up an S3 bucket, securing it, and sharing files is now effortless. Whether you're on Windows or Linux/macOS, you’re covered. No more manual work—just automation magic! ✨&lt;/p&gt;

&lt;p&gt;🚀 Happy Automating!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Cloud Computing Explained: IaaS, PaaS, SaaS – What the Heck Are They?</title>
      <dc:creator>Destiny Obs</dc:creator>
      <pubDate>Mon, 24 Mar 2025 10:13:45 +0000</pubDate>
      <link>https://dev.to/destinyobs/cloud-computing-explained-iaas-paas-saas-what-the-heck-are-they-55gj</link>
      <guid>https://dev.to/destinyobs/cloud-computing-explained-iaas-paas-saas-what-the-heck-are-they-55gj</guid>
      <description>&lt;h2&gt;
  
  
  🚀 &lt;strong&gt;So, You Want to Understand Cloud Computing?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Great! But let me warn you—if you've ever tried explaining cloud computing to a friend, you’ve probably seen their eyes glaze over like a Windows update stuck at 99%.  &lt;/p&gt;

&lt;p&gt;Fear not! I’m here to &lt;strong&gt;decode the cloud madness&lt;/strong&gt;, break down &lt;strong&gt;IaaS, PaaS, and SaaS&lt;/strong&gt;, and—who knows?—maybe even make you laugh a little.  &lt;/p&gt;

&lt;p&gt;Let’s dive in.  &lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Welcome to the Cloud Buffet&lt;/strong&gt; ☁️🍽️
&lt;/h2&gt;

&lt;p&gt;Well, cause i love food, let's use this... Imagine you walk into a &lt;strong&gt;cloud computing restaurant&lt;/strong&gt;. You’re hungry, but how much effort do you want to put into your meal?  &lt;/p&gt;

&lt;p&gt;You’ve got &lt;strong&gt;three choices&lt;/strong&gt;:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;IaaS (Infrastructure as a Service):&lt;/strong&gt; You buy raw ingredients, rent a kitchen, and cook your own meal.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PaaS (Platform as a Service):&lt;/strong&gt; You get a &lt;strong&gt;prepped kitchen, pre-cut ingredients&lt;/strong&gt;, and just need to cook.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SaaS (Software as a Service):&lt;/strong&gt; You sit back, order from the menu, and enjoy—zero effort.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s break them down properly.  &lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;IaaS: The DIY Cloud (You Like Full Control, Eh?)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;🛠️ &lt;strong&gt;What is IaaS?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Infrastructure as a Service (IaaS)&lt;/strong&gt; is like renting a &lt;strong&gt;virtual data center&lt;/strong&gt;. You get &lt;strong&gt;bare-bones computing power&lt;/strong&gt;—servers, storage, networking—but &lt;strong&gt;you&lt;/strong&gt; are responsible for installing, configuring, and managing everything on top.  &lt;/p&gt;

&lt;p&gt;It’s perfect for DevOps engineers and sysadmins who &lt;strong&gt;love control&lt;/strong&gt; and don’t mind getting their hands dirty.  &lt;/p&gt;

&lt;p&gt;🔥 &lt;strong&gt;Real-world Example&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Think &lt;strong&gt;AWS EC2, Google Compute Engine, Microsoft Azure VMs&lt;/strong&gt;. You spin up a virtual machine, install an OS, configure networking, and boom—you have a server in the cloud.  &lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;Why Choose IaaS?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
✅ You need full control over the system.&lt;br&gt;&lt;br&gt;
✅ You want to run custom applications or complex enterprise software.&lt;br&gt;&lt;br&gt;
✅ You enjoy feeling like a cloud god, managing your own infrastructure.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;⛔ But Beware!&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
❌ You’re responsible for security, patches, and scaling.&lt;br&gt;&lt;br&gt;
❌ Misconfigurations can lead to crazy costs. (Ever left an AWS EC2 instance running all month? RIP your wallet.)  &lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;PaaS: The "Chef-Prepared" Cloud (For Developers Who Hate DevOps)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;👨‍🍳 &lt;strong&gt;What is PaaS?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Platform as a Service (PaaS)&lt;/strong&gt; is &lt;strong&gt;IaaS with the hard parts managed for you&lt;/strong&gt;. It gives you a &lt;strong&gt;pre-configured environment&lt;/strong&gt; with an OS, middleware, and runtime—just &lt;strong&gt;bring your code&lt;/strong&gt; and deploy.  &lt;/p&gt;

&lt;p&gt;PaaS is like walking into a restaurant with &lt;strong&gt;everything prepped&lt;/strong&gt;—just follow the recipe, and your dish is ready.  &lt;/p&gt;

&lt;p&gt;🔥 &lt;strong&gt;Real-world Example&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Think &lt;strong&gt;Heroku, AWS Elastic Beanstalk, Google App Engine, or Azure App Service&lt;/strong&gt;. You just push your app, and the platform handles infrastructure, scaling, and networking.  &lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;Why Choose PaaS?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
✅ You’re a &lt;strong&gt;developer&lt;/strong&gt; and don’t want to waste time setting up infrastructure.&lt;br&gt;&lt;br&gt;
✅ You want auto-scaling and managed deployments.&lt;br&gt;&lt;br&gt;
✅ You like focusing on coding while someone else handles servers.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;⛔ But Beware!&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
❌ Less flexibility—you can’t tweak everything.&lt;br&gt;&lt;br&gt;
❌ Some platforms lock you into their ecosystem. (Vendor lock-in is real, folks.)  &lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;SaaS: The Lazy Cloud (Just Use It, No Work Needed)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;🛋️ &lt;strong&gt;What is SaaS?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Software as a Service (SaaS)&lt;/strong&gt; is &lt;strong&gt;ready-to-use software&lt;/strong&gt; in the cloud. No installation, no configuration—just &lt;strong&gt;log in and get to work&lt;/strong&gt;.  &lt;/p&gt;

&lt;p&gt;Imagine walking into a restaurant, ordering from a menu, and having a delicious meal served. &lt;strong&gt;No cooking, no stress.&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;🔥 &lt;strong&gt;Real-world Example&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Gmail? &lt;strong&gt;SaaS.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Netflix? &lt;strong&gt;SaaS.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Google Docs, Zoom, Slack? &lt;strong&gt;All SaaS.&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;Why Choose SaaS?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
✅ You want something that &lt;strong&gt;just works&lt;/strong&gt; without setting up infrastructure.&lt;br&gt;&lt;br&gt;
✅ You need easy access from any device.&lt;br&gt;&lt;br&gt;
✅ Your company doesn’t want to manage software updates.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;⛔ But Beware!&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
❌ You have &lt;strong&gt;zero control&lt;/strong&gt; over the software.&lt;br&gt;&lt;br&gt;
❌ If the provider goes down, you go down with them. (Looking at you, Zoom outage of 2020.)  &lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;IaaS vs. PaaS vs. SaaS – The Ultimate Showdown&lt;/strong&gt;
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;IaaS&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;PaaS&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;SaaS&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Who manages it?&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;You&lt;/td&gt;
&lt;td&gt;Cloud provider (mostly)&lt;/td&gt;
&lt;td&gt;Cloud provider (completely)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Flexibility&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ease of Use&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Hard&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Easy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Examples&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AWS EC2, Google Compute Engine&lt;/td&gt;
&lt;td&gt;Heroku, Google App Engine&lt;/td&gt;
&lt;td&gt;Gmail, Netflix, Zoom&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best for?&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;DevOps engineers&lt;/td&gt;
&lt;td&gt;Developers&lt;/td&gt;
&lt;td&gt;End-users&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Beyond IaaS, PaaS, and SaaS: The Other "aaS" Models You Should Know&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Cloud computing doesn’t stop at these three—oh no, the &lt;strong&gt;aaS (as a Service) family&lt;/strong&gt; has expanded like a Marvel franchise:  &lt;/p&gt;

&lt;p&gt;🕵️ &lt;strong&gt;FaaS (Function as a Service)&lt;/strong&gt; → Serverless computing where your code runs on demand. Think &lt;strong&gt;AWS Lambda, Google Cloud Functions&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
🐳 &lt;strong&gt;CaaS (Container as a Service)&lt;/strong&gt; → Managed container orchestration. Think &lt;strong&gt;AWS Fargate, GKE&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
💾 &lt;strong&gt;DBaaS (Database as a Service)&lt;/strong&gt; → Fully managed databases. Think &lt;strong&gt;AWS RDS, Firebase&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
🔗 &lt;strong&gt;BaaS (Backend as a Service)&lt;/strong&gt; → No need to build a backend! Think &lt;strong&gt;Firebase, Supabase&lt;/strong&gt;.  &lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Final Thoughts – Which Cloud Model Should You Choose?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;🔹 Are you a control freak who loves managing infrastructure?&lt;/strong&gt; → &lt;strong&gt;Go for IaaS.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;🔹 Are you a developer who just wants to code and deploy?&lt;/strong&gt; → &lt;strong&gt;PaaS is your best friend.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;🔹 Do you want a fully managed experience with no headaches?&lt;/strong&gt; → &lt;strong&gt;SaaS is the way.&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;At the end of the day, cloud computing isn’t just about acronyms—it’s about &lt;strong&gt;choosing the right tool for the job&lt;/strong&gt;.  &lt;/p&gt;

&lt;p&gt;And now that you know &lt;strong&gt;IaaS, PaaS, and SaaS&lt;/strong&gt;, you can finally explain them to your friends &lt;strong&gt;without boring them to death&lt;/strong&gt;. 🎉  &lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;What’s Next?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;🚀 Want to try IaaS? &lt;strong&gt;Spin up an AWS EC2 instance.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
🚀 Want to test PaaS? &lt;strong&gt;Deploy a Node.js app on Heroku.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
🚀 Want to use SaaS? &lt;strong&gt;Just keep using Gmail. 😆&lt;/strong&gt;  &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%2F15wee1dp0me4qn7b8o5a.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%2F15wee1dp0me4qn7b8o5a.jpg" alt="Image description" width="800" height="592"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>cloud</category>
      <category>cloudcomputing</category>
      <category>newbie</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Destiny Obs</dc:creator>
      <pubDate>Mon, 16 Dec 2024 13:39:39 +0000</pubDate>
      <link>https://dev.to/destinyobs/-39nc</link>
      <guid>https://dev.to/destinyobs/-39nc</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/favxlaw" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&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%2F1673424%2Fe7aa58e9-2f38-4ddb-a697-61240e8b812b.png" alt="favxlaw"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/favxlaw/automated-load-testing-in-cicd-pipelines-lessons-from-a-custom-bash-script-3d97" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Automated Load Testing in CI/CD Pipelines: Lessons from a Custom Bash Script&lt;/h2&gt;
      &lt;h3&gt;Favour Lawrence ・ Dec 16&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#devops&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#programming&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#tutorial&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>testing</category>
      <category>devops</category>
      <category>automation</category>
    </item>
  </channel>
</rss>
