<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Sohag's Notes]]></title><description><![CDATA[Tech Lead at MobyPay | Certified Laravel Developer | PHP JS GO | DevOps Enthusiast | Open to projects]]></description><link>https://notes.sohag.pro</link><generator>RSS for Node</generator><lastBuildDate>Tue, 14 Apr 2026 19:15:24 GMT</lastBuildDate><atom:link href="https://notes.sohag.pro/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Starlink + ISP Failover Setup]]></title><description><![CDATA[🚀 Starlink + ISP Failover Setup: A Beginner’s Guide to Bulletproof Internet at Home
Imagine you're in the middle of an important Zoom call — and suddenly your internet cuts out. Your heart skips a beat. That dreaded buffering circle spins on the scr...]]></description><link>https://notes.sohag.pro/starlink-isp-failover-setup</link><guid isPermaLink="true">https://notes.sohag.pro/starlink-isp-failover-setup</guid><category><![CDATA[Starlink]]></category><category><![CDATA[#Mikrotik]]></category><dc:creator><![CDATA[Sohag Hasan]]></dc:creator><pubDate>Wed, 04 Jun 2025 20:15:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1749068019738/96a6c4fa-6272-43f5-8b0f-dc138a2f0df6.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-starlink-isp-failover-setup-a-beginners-guide-to-bulletproof-internet-at-home">🚀 Starlink + ISP Failover Setup: A Beginner’s Guide to Bulletproof Internet at Home</h1>
<p>Imagine you're in the middle of an important Zoom call — and suddenly your internet cuts out. Your heart skips a beat. That dreaded buffering circle spins on the screen. You're disconnected.</p>
<p>Now imagine instead: the internet <em>switches seamlessly</em> to a backup connection. Your meeting continues without a glitch.</p>
<p>That’s the power of <strong>failover internet</strong>. In this guide, I’ll show you how I used <strong>Starlink as primary internet</strong> and a <strong>local ISP via PPPoE as backup</strong>, with the help of a <strong>MikroTik router</strong> — and how you can do the same.</p>
<p>Whether you work from home, stream content, or run a smart home — this setup adds peace of mind and productivity.</p>
<hr />
<h2 id="heading-hardware-i-used">🧰 Hardware I Used</h2>
<ul>
<li><p><strong>MikroTik hEX S (RB760iGS)</strong> — compact and powerful router</p>
</li>
<li><p><strong>TP-Link Deco M4 Mesh (3 units)</strong> — for strong Wi-Fi across the house</p>
</li>
<li><p><strong>Windows PC</strong> — for initial configuration</p>
</li>
</ul>
<hr />
<h2 id="heading-the-big-picture">⚙️ The Big Picture</h2>
<p>We’ll configure:</p>
<ul>
<li><p><strong>Starlink (ether1)</strong> as the main internet (DHCP)</p>
</li>
<li><p><strong>Local ISP (ether2)</strong> using <strong>PPPoE</strong> as backup</p>
</li>
<li><p><strong>Failover logic</strong> so the router automatically switches when Starlink fails</p>
</li>
<li><p><strong>LAN setup</strong> with DHCP + NAT</p>
</li>
<li><p>Optional: <strong>MAC spoofing</strong>, <strong>DNS</strong>, and <strong>firewall basics</strong></p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1749068039836/781f6bd5-e4de-4c37-950c-cb1c3925e789.png" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-step-by-step-setup-beginner-friendly">🪜 Step-by-Step Setup (Beginner Friendly)</h2>
<hr />
<h3 id="heading-step-1-connect-to-your-mikrotik-router">🔌 Step 1: Connect to Your MikroTik Router</h3>
<ol>
<li><p>Plug your <strong>Windows PC</strong> into <strong>ether2–ether5</strong> on the MikroTik router (avoid ether1 — that’s for internet input).</p>
</li>
<li><p>On Windows, open <code>ncpa.cpl</code>, select your Ethernet adapter &gt; Properties &gt; TCP/IPv4 → Set to “Obtain IP automatically”.</p>
</li>
<li><p>Your PC should get an IP like <code>192.168.88.x</code>.</p>
</li>
</ol>
<hr />
<h3 id="heading-step-2-login-to-mikrotik-via-winbox">💻 Step 2: Login to MikroTik via Winbox</h3>
<ol>
<li><p>Download Winbox from: <a target="_blank" href="https://mikrotik.com/download">mikrotik.com/download</a></p>
</li>
<li><p>Open it — no install needed.</p>
</li>
<li><p>Look under the <strong>Neighbors</strong> tab — you’ll see your router’s MAC and IP (<code>192.168.88.1</code>)</p>
</li>
<li><p>Connect using:</p>
<ul>
<li><p><strong>Username:</strong> <code>admin</code></p>
</li>
<li><p><strong>Password:</strong> <em>(Check router label or leave blank for first login)</em></p>
</li>
</ul>
</li>
<li><p>Click <strong>Connect</strong></p>
</li>
</ol>
<hr />
<h3 id="heading-step-3-initial-router-setup">🔧 Step 3: Initial Router Setup</h3>
<ol>
<li><p><strong>Change the admin password</strong></p>
<ul>
<li>Go to: <strong>System &gt; Users &gt; admin &gt; Set Password</strong></li>
</ul>
</li>
<li><p><strong>Update RouterOS</strong></p>
<ul>
<li><p>Go to: <strong>System &gt; Packages &gt; Check for Updates &gt; Download &amp; Install</strong></p>
</li>
<li><p>Channel: <code>stable</code></p>
</li>
</ul>
</li>
</ol>
<p>Router will reboot. Reconnect after that.</p>
<hr />
<h2 id="heading-wan-configuration">🌐 WAN Configuration</h2>
<hr />
<h3 id="heading-step-4-connect-wan-sources">🔌 Step 4: Connect WAN Sources</h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Port</td><td>Use</td></tr>
</thead>
<tbody>
<tr>
<td><code>ether1</code></td><td>Starlink Ethernet Adapter</td></tr>
<tr>
<td><code>ether2</code></td><td>ISP modem/router (PPPoE)</td></tr>
</tbody>
</table>
</div><hr />
<h3 id="heading-step-5-set-starlink-as-primary-wan">🚀 Step 5: Set Starlink as Primary WAN</h3>
<ol>
<li><p>Go to <strong>IP &gt; DHCP Client</strong></p>
</li>
<li><p>Click <code>+</code></p>
</li>
<li><p>Set <strong>Interface</strong> to <code>ether1</code></p>
</li>
<li><p>Click <strong>Apply</strong> and **OK`</p>
</li>
</ol>
<p>✅ Starlink will now get a dynamic IP as your <strong>primary internet</strong>.</p>
<hr />
<h3 id="heading-step-6-set-up-isp-as-backup-via-pppoe">🌍 Step 6: Set Up ISP as Backup via PPPoE</h3>
<ol>
<li><p>Go to <strong>Interfaces &gt; + &gt; PPPoE Client</strong></p>
</li>
<li><p>Set:</p>
<ul>
<li><p><strong>Name</strong>: <code>pppoe-out1</code></p>
</li>
<li><p><strong>Interface</strong>: <code>ether2</code></p>
</li>
</ul>
</li>
<li><p>In <strong>Dial Out</strong> tab:</p>
<ul>
<li><p>Username: <code>your-pppoe-username</code></p>
</li>
<li><p>Password: <code>your-password</code></p>
</li>
<li><p>Enable: <strong>Add Default Route</strong></p>
</li>
<li><p>Set <strong>Default Route Distance</strong>: <code>2</code></p>
</li>
</ul>
</li>
<li><p>Apply and OK</p>
</li>
</ol>
<p>✅ This ensures PPPoE acts as a <strong>failover connection</strong> (lower priority than Starlink).</p>
<hr />
<h3 id="heading-step-7-lan-setup-home-devices">📶 Step 7: LAN Setup (Home Devices)</h3>
<ol>
<li><p>Go to <strong>Bridge &gt; Add New Bridge</strong></p>
</li>
<li><p>Add <strong>ether3 to ether5</strong> to the bridge</p>
</li>
<li><p>Go to <strong>IP &gt; DHCP Server &gt; Setup</strong></p>
<ul>
<li><p>Choose bridge as interface</p>
</li>
<li><p>Set default IP range (e.g., <code>192.168.88.0/24</code>)</p>
</li>
</ul>
</li>
<li><p>Go to <strong>IP &gt; Firewall &gt; NAT</strong></p>
<ul>
<li><p>Add <strong>masquerade rules</strong> for:</p>
<ul>
<li><ul>
<li><p>Out Interface: <code>ether1</code> → Action: masquerade</p>
<ul>
<li>Out Interface: <code>pppoe-out1</code> → Action: masquerade</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ol>
<p>✅ Now all LAN devices can share internet via both connections.</p>
<hr />
<h3 id="heading-step-8-failover-in-action">🧠 Step 8: Failover in Action</h3>
<p>Go to <strong>IP &gt; Routes</strong> — you should see:</p>
<ul>
<li><p>Starlink → distance <code>1</code></p>
</li>
<li><p>PPPoE → distance <code>2</code></p>
</li>
</ul>
<p>If Starlink fails, MikroTik auto-switches to the PPPoE route.</p>
<blockquote>
<p>💡 <strong>Warm failover</strong>: It’s fast, not instant. No downtime for most tasks (buffering may happen once).</p>
</blockquote>
<hr />
<h2 id="heading-advanced-tips-optional-but-useful">🧪 Advanced Tips (Optional but Useful)</h2>
<hr />
<h3 id="heading-script-based-netwatch-for-active-failover">🔄 Script-Based Netwatch (For Active Failover)</h3>
<p>If you want <strong>faster detection</strong>, set up <strong>Netwatch</strong>:</p>
<ul>
<li><p>Go to <strong>Tools &gt; Netwatch</strong></p>
</li>
<li><p>Monitor a reliable IP (e.g., <code>8.8.8.8</code>)</p>
</li>
<li><p>On <strong>Down</strong>, disable Starlink route</p>
</li>
<li><p>On <strong>Up</strong>, re-enable it</p>
</li>
</ul>
<hr />
<h3 id="heading-spoof-mac-address-if-isp-locks-it">🧙 Spoof MAC Address (If ISP Locks It)</h3>
<p>Some ISPs only allow internet on registered MACs.</p>
<p>To clone MAC on <code>ether2</code>:</p>
<pre><code class="lang-bash">/interface ethernet <span class="hljs-built_in">set</span> ether2 mac-address=XX:XX:XX:XX:XX:XX
</code></pre>
<p>Then confirm under <strong>Interfaces &gt; ether2</strong></p>
<hr />
<h3 id="heading-setup-dns">🌐 Setup DNS</h3>
<ol>
<li><p>Go to <strong>IP &gt; DNS</strong></p>
</li>
<li><p>Add:</p>
<ul>
<li><p><code>8.8.8.8</code> (Google)</p>
</li>
<li><p><code>1.1.1.1</code> (Cloudflare)</p>
</li>
</ul>
</li>
<li><p>Enable <strong>Allow Remote Requests</strong></p>
</li>
</ol>
<p>✅ This helps your LAN devices resolve domains via MikroTik.</p>
<hr />
<h2 id="heading-you-did-it">🎉 You Did It!</h2>
<p>You now have a <strong>smart home internet setup</strong> with:</p>
<p>✅ <strong>Primary internet</strong> from Starlink<br />✅ <strong>Automatic failover</strong> to ISP (PPPoE)<br />✅ Seamless recovery when Starlink is back<br />✅ Stable internet for work, video calls, gaming, and streaming</p>
<hr />
<h2 id="heading-real-life-example-why-i-needed-this">👨‍💻 Real Life Example: Why I Needed This</h2>
<p>I live in a semi-urban area where power cuts or weather often interrupt traditional ISP service. Starlink provides excellent uptime — but even satellite can sometimes drop.</p>
<p>Thanks to this setup, when Starlink stutters, my MikroTik router quietly shifts over to my ISP. I keep working, the Netflix show doesn’t stop, and my smart lights stay responsive.</p>
<p>It’s like having internet insurance — and it’s worth every minute of setup.</p>
<hr />
<h2 id="heading-whats-next">🧭 What’s Next?</h2>
<p>Now that you're comfortable with MikroTik basics, you can explore:</p>
<ul>
<li><p>🔐 <strong>Firewall rules</strong></p>
</li>
<li><p>🎛️ <strong>Bandwidth control</strong></p>
</li>
<li><p>🧅 <strong>VPN access to your home</strong></p>
</li>
<li><p>🧰 <strong>Remote monitoring and management</strong></p>
</li>
</ul>
<hr />
<h2 id="heading-questions-or-feedback">💬 Questions or Feedback?</h2>
<p>Drop a comment below if you run into any issues or want me to cover more advanced MikroTik topics. Happy networking!</p>
]]></content:encoded></item><item><title><![CDATA[How to Deploy a Next.js App on cPanel]]></title><description><![CDATA[🚀 How to Deploy a Next.js App on cPanel (A Beginner-Friendly Guide)
Hey friend! 👋You've built your awesome Next.js app and now you're ready to show it off to the world. But… you're on cPanel hosting and not sure what to do next?
No worries—I’ll wal...]]></description><link>https://notes.sohag.pro/deploy-a-nextjs-app-on-cpanel</link><guid isPermaLink="true">https://notes.sohag.pro/deploy-a-nextjs-app-on-cpanel</guid><category><![CDATA[Next.js]]></category><category><![CDATA[cpanel]]></category><dc:creator><![CDATA[Sohag Hasan]]></dc:creator><pubDate>Mon, 05 May 2025 11:26:38 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1746444332746/9117f925-bab5-4131-bb12-e3b9a03f18c8.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-how-to-deploy-a-nextjs-app-on-cpanel-a-beginner-friendly-guide">🚀 How to Deploy a Next.js App on cPanel (A Beginner-Friendly Guide)</h1>
<p>Hey friend! 👋<br />You've built your awesome Next.js app and now you're ready to show it off to the world. But… you're on cPanel hosting and not sure what to do next?</p>
<p>No worries—I’ll walk you through everything like we’re sitting side by side. ☕️<br />This guide is perfect for <strong>beginners</strong> who are trying to deploy a Next.js app on cPanel the smart way.</p>
<hr />
<h2 id="heading-what-youll-need-first">🧰 What You’ll Need First</h2>
<p>Before diving in, make sure you’ve got:</p>
<ul>
<li><p>✅ A Next.js app (already created and tested locally)</p>
</li>
<li><p>✅ A cPanel-based hosting account (shared or VPS)</p>
</li>
<li><p>✅ A domain name connected to your cPanel</p>
</li>
</ul>
<p><strong>Optional but helpful:</strong> Basic knowledge of how file managers and terminal commands work.</p>
<hr />
<h2 id="heading-a-quick-note-about-npm-vs-yarn">⚠️ A Quick Note About <code>npm</code> vs <code>yarn</code></h2>
<p>These are <strong>two different package managers</strong> that do the same job: they install and run packages (like Next.js, React, etc.).</p>
<h3 id="heading-if-you-used-npm-to-create-your-project-keep-using-npm">🟢 If you used <code>npm</code> to create your project, keep using <code>npm</code>.</h3>
<h3 id="heading-if-you-used-yarn-to-create-your-project-stick-with-yarn">🔵 If you used <code>yarn</code> to create your project, stick with <code>yarn</code>.</h3>
<p><strong>Do NOT use both.</strong> Pick the one you started with and use only that throughout the guide.</p>
<hr />
<h2 id="heading-step-1-create-a-custom-server-file">🛠 Step 1: Create a Custom Server File</h2>
<p>Most Next.js apps are designed to be run on Vercel or similar platforms. But since we’re on cPanel, we need a custom server using Node.js.</p>
<h3 id="heading-in-your-project-root-create-a-new-file-manually-named-serverjs-or-from-the-terminal-using-the-below-command">➕ In your project root, create a new file manually named <code>server.js</code> or from the terminal using the below command:</h3>
<pre><code class="lang-bash">touch server.js
</code></pre>
<p>Paste this code into <code>server.js</code>:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> { createServer } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'http'</span>)
<span class="hljs-keyword">const</span> { parse } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'url'</span>)
<span class="hljs-keyword">const</span> next = <span class="hljs-built_in">require</span>(<span class="hljs-string">'next'</span>)

<span class="hljs-keyword">const</span> dev = process.env.NODE_ENV !== <span class="hljs-string">'production'</span>
<span class="hljs-keyword">const</span> hostname = <span class="hljs-string">'localhost'</span>
<span class="hljs-keyword">const</span> port = process.env.PORT || <span class="hljs-number">3000</span>

<span class="hljs-keyword">const</span> app = next({ dev, hostname, port })
<span class="hljs-keyword">const</span> handle = app.getRequestHandler()

app.prepare().then(<span class="hljs-function">() =&gt;</span> {
  createServer(<span class="hljs-keyword">async</span> (req, res) =&gt; {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> parsedUrl = parse(req.url, <span class="hljs-literal">true</span>)
      <span class="hljs-keyword">await</span> handle(req, res, parsedUrl)
    } <span class="hljs-keyword">catch</span> (err) {
      <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error occurred handling'</span>, req.url, err)
      res.statusCode = <span class="hljs-number">500</span>
      res.end(<span class="hljs-string">'internal server error'</span>)
    }
  }).listen(port, <span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span> (err) <span class="hljs-keyword">throw</span> err
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`&gt; Ready on http://<span class="hljs-subst">${hostname}</span>:<span class="hljs-subst">${port}</span>`</span>)
  })
})
</code></pre>
<p>This file is like the traffic cop for your app, making sure every request gets routed properly.</p>
<hr />
<h2 id="heading-step-2-update-your-packagejson">🧾 Step 2: Update Your <code>package.json</code></h2>
<p>Tell your app how to start in production using the server you just created.</p>
<p>Open your <code>package.json</code> file and change the <code>scripts</code> section like this:</p>
<pre><code class="lang-json"><span class="hljs-string">"scripts"</span>: {
  <span class="hljs-comment">//... Do not change other commands just the "start" command</span>
  <span class="hljs-attr">"start"</span>: <span class="hljs-string">"NODE_ENV=production node server.js"</span>
}
</code></pre>
<blockquote>
<p>This will allow you to run <code>npm start</code> or <code>yarn start</code> later, depending on your package manager.</p>
</blockquote>
<hr />
<h2 id="heading-step-3-build-your-app">🧱 Step 3: Build Your App</h2>
<p>We need to prepare your app for production (i.e., make it fast and optimized).</p>
<h3 id="heading-if-youre-using-npm-run">👉 If you’re using <strong>npm</strong>, run:</h3>
<pre><code class="lang-bash">npm run build
</code></pre>
<h3 id="heading-if-youre-using-yarn-run">👉 If you’re using <strong>yarn</strong>, run:</h3>
<pre><code class="lang-bash">yarn build
</code></pre>
<p>This will generate a <code>.next</code> folder containing the production-ready version of your app.</p>
<hr />
<h2 id="heading-step-4-zip-your-app-for-upload">📦 Step 4: Zip Your App for Upload</h2>
<p>You now need to package your app (without the junk) to upload to cPanel.</p>
<h3 id="heading-select-all-project-files-except">✅ Select all project files <strong>except</strong>:</h3>
<ul>
<li><p><code>node_modules/</code></p>
</li>
<li><p><code>.git/</code></p>
</li>
<li><p><code>.gitignore</code></p>
</li>
<li><p><code>README.md</code></p>
</li>
</ul>
<h3 id="heading-then-compress-everything-into-a-zip-file">📁 Then compress everything into a <code>.zip</code> file.</h3>
<p>You can name it <code>nextjs-app.zip</code> or anything you like.</p>
<hr />
<h2 id="heading-step-5-upload-and-extract-on-cpanel">📂 Step 5: Upload and Extract on cPanel</h2>
<ol>
<li><p>Log into your <strong>cPanel dashboard</strong></p>
</li>
<li><p>Open the <strong>File Manager</strong></p>
</li>
<li><p>Navigate to the directory where your domain lives (usually <code>public_html/</code>)</p>
</li>
<li><p>Upload your <code>.zip</code> file</p>
</li>
<li><p>Once uploaded, right-click the file and select <strong>Extract</strong></p>
</li>
</ol>
<p>You should now see all your app files inside the correct folder.</p>
<hr />
<h2 id="heading-step-6-set-up-the-nodejs-app-in-cpanel">⚙️ Step 6: Set Up the Node.js App in cPanel</h2>
<ol>
<li><p>Scroll down to the <strong>Software</strong> section in cPanel</p>
</li>
<li><p>Click on <strong>Setup Node.js App</strong></p>
</li>
<li><p>Click <strong>Create Application</strong></p>
</li>
</ol>
<h3 id="heading-fill-in-the-following">Fill in the following:</h3>
<ul>
<li><p><strong>Node.js version</strong>: Choose the one that matches your development environment (e.g., 22.x)</p>
</li>
<li><p><strong>Application mode</strong>: <code>Production</code></p>
</li>
<li><p><strong>Application root</strong>: The folder where your files were extracted (e.g., <code>public_html/nextjs-app</code>)</p>
</li>
<li><p><strong>Application URL</strong>: Your domain or subdomain</p>
</li>
<li><p><strong>Application startup file</strong>: <code>server.js</code></p>
</li>
</ul>
<p>Now hit <strong>Create</strong>—cPanel will set up the environment for your app.</p>
<hr />
<h2 id="heading-step-7-install-project-dependencies">📥 Step 7: Install Project Dependencies</h2>
<p>Your app needs packages (like Next.js, React, etc.) to run. Time to install them.</p>
<h3 id="heading-option-1-use-the-cpanel-gui">👉 Option 1: Use the cPanel GUI</h3>
<ol>
<li><p>Go to your Node.js App list</p>
</li>
<li><p>Click <strong>Stop App</strong> (temporarily stop it)</p>
</li>
<li><p>Scroll down and click <strong>Run NPM Install</strong></p>
</li>
</ol>
<blockquote>
<p>If you used <strong>npm</strong> when creating the app, this is perfect. If you used <strong>yarn</strong>, you'll need to install via SSH (next step).</p>
</blockquote>
<hr />
<h3 id="heading-option-2-use-ssh-for-yarn-users-or-advanced-installs">👉 Option 2: Use SSH (for Yarn users or advanced installs)</h3>
<p>If your hosting allows SSH access:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> ~/public_html/your-app-folder
</code></pre>
<p>Then install packages:</p>
<h4 id="heading-for-npm-users">For <strong>npm</strong> users:</h4>
<pre><code class="lang-bash">npm install
</code></pre>
<h4 id="heading-for-yarn-users">For <strong>yarn</strong> users:</h4>
<pre><code class="lang-bash">yarn install
</code></pre>
<p>Once complete, go back to cPanel and click <strong>Start App</strong> again.</p>
<hr />
<h2 id="heading-step-8-youre-live">🎉 Step 8: You’re Live!</h2>
<p>Open your browser, type your domain, and hit Enter…<br />If all went well—you’re now serving your beautiful Next.js app to the world!</p>
<hr />
<h2 id="heading-final-thoughts">🧠 Final Thoughts</h2>
<p>Deploying on cPanel might seem scary at first, especially if you're used to platforms like Vercel. But with a little effort, it works beautifully—even on shared hosting.</p>
<h3 id="heading-quick-recap">🔁 Quick Recap:</h3>
<ul>
<li><p>Created a custom <code>server.js</code></p>
</li>
<li><p>Built the app</p>
</li>
<li><p>Zipped and uploaded files</p>
</li>
<li><p>Set up Node.js on cPanel</p>
</li>
<li><p>Installed dependencies using either <strong>npm</strong> or <strong>yarn</strong></p>
</li>
<li><p>And finally—ran the app!</p>
</li>
</ul>
<hr />
<h2 id="heading-got-questions">💬 Got Questions?</h2>
<p>Drop them in the comments or reach out to me! I'm happy to help you troubleshoot or celebrate your deployment success 🚀</p>
<p>Happy coding! 🎉💻</p>
<p><strong>This blog is inspired from:</strong></p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://medium.com/@geevadon/how-to-deploy-a-next-js-app-on-cpanel-efficiently-c00c5eb860de">https://medium.com/@geevadon/how-to-deploy-a-next-js-app-on-cpanel-efficiently-c00c5eb860de</a></div>
]]></content:encoded></item><item><title><![CDATA[My Essential VSCode Extensions]]></title><description><![CDATA[Supercharging My Development Workflow: A Deep Dive into My Essential VSCode Extensions
In the ever-evolving world of software development, the right tools can make the difference between a good developer and a great one. Visual Studio Code has become...]]></description><link>https://notes.sohag.pro/my-essential-vscode-extensions</link><guid isPermaLink="true">https://notes.sohag.pro/my-essential-vscode-extensions</guid><category><![CDATA[vscode extensions]]></category><category><![CDATA[Scripting]]></category><dc:creator><![CDATA[Sohag Hasan]]></dc:creator><pubDate>Thu, 27 Mar 2025 11:42:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1743075228481/157b93ab-6b51-4dd0-9ac9-c777e47adcab.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-supercharging-my-development-workflow-a-deep-dive-into-my-essential-vscode-extensions"><strong>Supercharging My Development Workflow: A Deep Dive into My Essential VSCode Extensions</strong></h1>
<p>In the ever-evolving world of software development, the right tools can make the difference between a good developer and a great one. Visual Studio Code has become my go-to integrated development environment, and over time, I've curated a collection of extensions that have transformed my coding experience, boosting productivity, improving code quality, and making development more enjoyable.</p>
<h2 id="heading-how-ive-created-this-blog">How I’ve created this blog?</h2>
<p>Here is script and the steps: <a target="_blank" href="https://gist.github.com/sohag-pro/f17a6d02514f9260811614e2db5175d4">https://gist.github.com/sohag-pro/f17a6d02514f9260811614e2db5175d4</a></p>
<h2 id="heading-the-extensions-that-power-my-development"><strong>The Extensions That Power My Development</strong></h2>
<h3 id="heading-bookmarks"><strong>Bookmarks</strong></h3>
<p><strong>Publisher:</strong> Alessandro Fragnani</p>
<p><strong>Description:</strong> Mark lines and jump to them</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=alefragnani.bookmarks">Marketplace Link</a></p>
<h3 id="heading-laravel-extra-intellisense"><strong>Laravel Extra Intellisense</strong></h3>
<p><strong>Publisher:</strong> amir</p>
<p><strong>Description:</strong> better intellisense for laravel projects.</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=amiralizadeh9480.laravel-extra-intellisense">Marketplace Link</a></p>
<h3 id="heading-all-autocomplete"><strong>All Autocomplete</strong></h3>
<p><strong>Publisher:</strong> Atishay Jain</p>
<p><strong>Description:</strong> Create autocomplete items from open files in VSCode.</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=atishay-jain.all-autocomplete">Marketplace Link</a></p>
<h3 id="heading-tailwind-docs"><strong>Tailwind Docs</strong></h3>
<p><strong>Publisher:</strong> Austen Cameron</p>
<p><strong>Description:</strong> Easily access the Tailwind CSS documentation from within Code</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=austenc.tailwind-docs">Marketplace Link</a></p>
<h3 id="heading-json-crack"><strong>JSON Crack</strong></h3>
<p><strong>Publisher:</strong> Aykut SaraÃ§</p>
<p><strong>Description:</strong> Seamlessly visualize your JSON data instantly into graphs.</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=aykutsarac.jsoncrack-vscode">Marketplace Link</a></p>
<h3 id="heading-php-intelephense"><strong>PHP Intelephense</strong></h3>
<p><strong>Publisher:</strong> Ben Mewburn</p>
<p><strong>Description:</strong> PHP code intelligence for Visual Studio Code</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=bmewburn.vscode-intelephense-client">Marketplace Link</a></p>
<h3 id="heading-tailwind-shades"><strong>Tailwind Shades</strong></h3>
<p><strong>Publisher:</strong> Omar Bourhaouta</p>
<p><strong>Description:</strong> Tailwind CSS color palette generator</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=bourhaouta.tailwindshades">Marketplace Link</a></p>
<h3 id="heading-tailwind-css-intellisense"><strong>Tailwind CSS IntelliSense</strong></h3>
<p><strong>Publisher:</strong> Tailwind Labs</p>
<p><strong>Description:</strong> Intelligent Tailwind CSS tooling for VS Code</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss">Marketplace Link</a></p>
<h3 id="heading-turbo-console-log"><strong>Turbo Console Log</strong></h3>
<p><strong>Publisher:</strong> Anas Chakroun</p>
<p><strong>Description:</strong> Automating the process of writing meaningful log messages.</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=chakrounanas.turbo-console-log">Marketplace Link</a></p>
<h3 id="heading-gitignore"><strong>gitignore</strong></h3>
<p><strong>Publisher:</strong> CodeZombie</p>
<p><strong>Description:</strong> Lets you pull .gitignore templates from the <a target="_blank" href="https://github.com/github/gitignore">https://github.com/github/gitignore</a> repository. Language support for .gitignore files.</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=codezombiech.gitignore">Marketplace Link</a></p>
<h3 id="heading-laravel-goto-view"><strong>Laravel goto view</strong></h3>
<p><strong>Publisher:</strong> codingyu</p>
<p><strong>Description:</strong> Quick jump to view</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=codingyu.laravel-goto-view">Marketplace Link</a></p>
<h3 id="heading-dart"><strong>Dart</strong></h3>
<p><strong>Publisher:</strong> Dart Code</p>
<p><strong>Description:</strong> Dart language support and debugger for Visual Studio Code.</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=dart-code.dart-code">Marketplace Link</a></p>
<h3 id="heading-flutter"><strong>Flutter</strong></h3>
<p><strong>Publisher:</strong> Dart Code</p>
<p><strong>Description:</strong> Flutter support and debugger for Visual Studio Code.</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=dart-code.flutter">Marketplace Link</a></p>
<h3 id="heading-eslint"><strong>ESLint</strong></h3>
<p><strong>Publisher:</strong> Microsoft</p>
<p><strong>Description:</strong> Integrates ESLint JavaScript into VS Code.</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint">Marketplace Link</a></p>
<h3 id="heading-composer"><strong>Composer</strong></h3>
<p><strong>Publisher:</strong> DEVSENSE</p>
<p><strong>Description:</strong> All-in-One composer integration, quick actions, commands, automatic installation, tasks, code lenses, diagnostics, and composer.json IntelliSense.</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=devsense.composer-php-vscode">Marketplace Link</a></p>
<h3 id="heading-intelliphp-ai-autocomplete-for-php"><strong>IntelliPHP - AI Autocomplete for PHP</strong></h3>
<p><strong>Publisher:</strong> DEVSENSE</p>
<p><strong>Description:</strong> AI-assisted development for PHP.</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=devsense.intelli-php-vscode">Marketplace Link</a></p>
<h3 id="heading-php"><strong>PHP</strong></h3>
<p><strong>Publisher:</strong> DEVSENSE</p>
<p><strong>Description:</strong> All-in-One PHP support - IntelliSense, Debug, Formatter, Code Lenses, Code Fixes, Linting, Refactoring, PHPUnit Tests, Web Server, and more.</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=devsense.phptools-vscode">Marketplace Link</a></p>
<h3 id="heading-php-profiler"><strong>PHP Profiler</strong></h3>
<p><strong>Publisher:</strong> DEVSENSE</p>
<p><strong>Description:</strong> Support for PHP (Xdebug) profiling files and inspecting them.</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=devsense.profiler-php-vscode">Marketplace Link</a></p>
<h3 id="heading-gitlens-git-supercharged"><strong>GitLens — Git supercharged</strong></h3>
<p><strong>Publisher:</strong> GitKraken</p>
<p><strong>Description:</strong> Supercharge Git within VS Code - Visualize code authorship at a glance via Git blame annotations and CodeLens, seamlessly navigate and explore Git repositories, gain valuable insights via rich visualizations and powerful comparison commands, and so much more</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens">Marketplace Link</a></p>
<h3 id="heading-goto-route-controller-laravel"><strong>goto-route-controller-laravel</strong></h3>
<p><strong>Publisher:</strong> Erlang Parasu</p>
<p><strong>Description:</strong> laravel helper: go to route declaration, go to controller method declaration, find blade usage</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=erlangparasu.goto-route-controller-laravel">Marketplace Link</a></p>
<h3 id="heading-prettier-code-formatter"><strong>Prettier - Code formatter</strong></h3>
<p><strong>Publisher:</strong> Prettier</p>
<p><strong>Description:</strong> Code formatter using prettier</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode">Marketplace Link</a></p>
<h3 id="heading-auto-rename-tag"><strong>Auto Rename Tag</strong></h3>
<p><strong>Publisher:</strong> Jun Han</p>
<p><strong>Description:</strong> Auto rename paired HTML/XML tag</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=formulahendry.auto-rename-tag">Marketplace Link</a></p>
<h3 id="heading-openssl-configuration-syntax"><strong>OpenSSL Configuration Syntax</strong></h3>
<p><strong>Publisher:</strong> geeksharp</p>
<p><strong>Description:</strong> Syntax highlighting for OpenSSL configuration files (openssl.cnf)</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=geeksharp.openssl-configuration-file">Marketplace Link</a></p>
<h3 id="heading-github-copilot"><strong>GitHub Copilot</strong></h3>
<p><strong>Publisher:</strong> GitHub</p>
<p><strong>Description:</strong> Your AI pair programmer</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=github.copilot">Marketplace Link</a></p>
<h3 id="heading-github-copilot-chat"><strong>GitHub Copilot Chat</strong></h3>
<p><strong>Publisher:</strong> GitHub</p>
<p><strong>Description:</strong> AI chat features powered by Copilot</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=github.copilot-chat">Marketplace Link</a></p>
<h3 id="heading-github-actions"><strong>GitHub Actions</strong></h3>
<p><strong>Publisher:</strong> GitHub</p>
<p><strong>Description:</strong> GitHub Actions workflows and runs for <a target="_blank" href="http://github.com">github.com</a> hosted repositories in VS Code</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=github.vscode-github-actions">Marketplace Link</a></p>
<h3 id="heading-github-pull-requests"><strong>GitHub Pull Requests</strong></h3>
<p><strong>Publisher:</strong> GitHub</p>
<p><strong>Description:</strong> Pull Request and Issue Provider for GitHub</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=github.vscode-pull-request-github">Marketplace Link</a></p>
<h3 id="heading-todo-tree"><strong>Todo Tree</strong></h3>
<p><strong>Publisher:</strong> Gruntfuggly</p>
<p><strong>Description:</strong> Show TODO, FIXME, etc. comment tags in a tree view</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=gruntfuggly.todo-tree">Marketplace Link</a></p>
<h3 id="heading-hashicorp-terraform"><strong>HashiCorp Terraform</strong></h3>
<p><strong>Publisher:</strong> HashiCorp</p>
<p><strong>Description:</strong> Syntax highlighting and autocompletion for Terraform</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=hashicorp.terraform">Marketplace Link</a></p>
<h3 id="heading-laravel-blade-wrapper"><strong>Laravel Blade Wrapper</strong></h3>
<p><strong>Publisher:</strong> IHunte</p>
<p><strong>Description:</strong> An extension to wrap Blade directives</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=ihunte.laravel-blade-wrapper">Marketplace Link</a></p>
<h3 id="heading-hungry-delete"><strong>Hungry Delete</strong></h3>
<p><strong>Publisher:</strong> jasonlhy</p>
<p><strong>Description:</strong> To delete an entire block of whitespace or tab, and reduce the time programmers need to press backspace</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=jasonlhy.hungry-delete">Marketplace Link</a></p>
<h3 id="heading-lzgit"><strong>lzgit</strong></h3>
<p><strong>Publisher:</strong> jlalmes</p>
<p><strong>Description:</strong> LaZyGIT - FOR HYPER EFFICIENT DEVELOPERS.</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=jlalmes.lzgit">Marketplace Link</a></p>
<h3 id="heading-peacock"><strong>Peacock</strong></h3>
<p><strong>Publisher:</strong> John Papa</p>
<p><strong>Description:</strong> Subtly change the workspace color of your workspace. Ideal when you have multiple VS Code instances and you want to quickly identify which is which.</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=johnpapa.vscode-peacock">Marketplace Link</a></p>
<h3 id="heading-colorize"><strong>colorize</strong></h3>
<p><strong>Publisher:</strong> kamikillerto</p>
<p><strong>Description:</strong> A vscode extension to help visualize css colors in files.</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=kamikillerto.vscode-colorize">Marketplace Link</a></p>
<h3 id="heading-phpfmt-php-formatter"><strong>phpfmt - PHP formatter</strong></h3>
<p><strong>Publisher:</strong> kokororin</p>
<p><strong>Description:</strong> Integrates phpfmt into VS Code</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=kokororin.vscode-phpfmt">Marketplace Link</a></p>
<h3 id="heading-laravel"><strong>Laravel</strong></h3>
<p><strong>Publisher:</strong> Laravel</p>
<p><strong>Description:</strong> Official VS Code extension for Laravel</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=laravel.vscode-laravel">Marketplace Link</a></p>
<h3 id="heading-gpg-sign"><strong>GPG Sign</strong></h3>
<p><strong>Publisher:</strong> MÃ¡rio Garrido</p>
<p><strong>Description:</strong> GPG Encrypter/Decrypter/Sign</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=mariogarrido.gpg-sign">Marketplace Link</a></p>
<h3 id="heading-php-namespace-resolver"><strong>PHP Namespace Resolver</strong></h3>
<p><strong>Publisher:</strong> Mehedi Hassan</p>
<p><strong>Description:</strong> Import and expand php namespaces</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=mehedidracula.php-namespace-resolver">Marketplace Link</a></p>
<h3 id="heading-fluent-icons"><strong>Fluent Icons</strong></h3>
<p><strong>Publisher:</strong> Miguel Solorio</p>
<p><strong>Description:</strong> Fluent product icons for Visual Studio Code</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=miguelsolorio.fluent-icons">Marketplace Link</a></p>
<h3 id="heading-remote-ssh"><strong>Remote - SSH</strong></h3>
<p><strong>Publisher:</strong> Microsoft</p>
<p><strong>Description:</strong> Open any folder on a remote machine using SSH and take advantage of VS Code's full feature set.</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh">Marketplace Link</a></p>
<h3 id="heading-remote-ssh-editing-configuration-files"><strong>Remote - SSH: Editing Configuration Files</strong></h3>
<p><strong>Publisher:</strong> Microsoft</p>
<p><strong>Description:</strong> Edit SSH configuration files</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh-edit">Marketplace Link</a></p>
<h3 id="heading-remote-explorer"><strong>Remote Explorer</strong></h3>
<p><strong>Publisher:</strong> Microsoft</p>
<p><strong>Description:</strong> View remote machines for SSH and Tunnels.</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=ms-vscode.remote-explorer">Marketplace Link</a></p>
<h3 id="heading-paste-image"><strong>Paste Image</strong></h3>
<p><strong>Publisher:</strong> mushan</p>
<p><strong>Description:</strong> paste image from clipboard directly</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=mushan.vscode-paste-image">Marketplace Link</a></p>
<h3 id="heading-laravel-goto-components"><strong>laravel-goto-components</strong></h3>
<p><strong>Publisher:</strong> naoray</p>
<p><strong>Description:</strong> Quick jump to components</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=naoray.laravel-goto-components">Marketplace Link</a></p>
<h3 id="heading-back-amp-forth"><strong>Back &amp; Forth</strong></h3>
<p><strong>Publisher:</strong> Nick Rudenko</p>
<p><strong>Description:</strong> Adds go back/forward buttons for easier navigation</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=nick-rudenko.back-n-forth">Marketplace Link</a></p>
<h3 id="heading-indent-rainbow"><strong>indent-rainbow</strong></h3>
<p><strong>Publisher:</strong> oderwat</p>
<p><strong>Description:</strong> Makes indentation easier to read</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=oderwat.indent-rainbow">Marketplace Link</a></p>
<h3 id="heading-laravel-blade-snippets"><strong>Laravel Blade Snippets</strong></h3>
<p><strong>Publisher:</strong> Winnie Lin</p>
<p><strong>Description:</strong> Laravel blade snippets and syntax highlight support</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=onecentlin.laravel-blade">Marketplace Link</a></p>
<h3 id="heading-laravel-extension-pack"><strong>Laravel Extension Pack</strong></h3>
<p><strong>Publisher:</strong> Winnie Lin</p>
<p><strong>Description:</strong> A collection of extensions for Laravel development</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=onecentlin.laravel-extension-pack">Marketplace Link</a></p>
<h3 id="heading-laravel-snippets"><strong>Laravel Snippets</strong></h3>
<p><strong>Publisher:</strong> Winnie Lin</p>
<p><strong>Description:</strong> Laravel snippets for Visual Studio Code (Support Laravel 5 and above)</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=onecentlin.laravel5-snippets">Marketplace Link</a></p>
<h3 id="heading-laravel-pint"><strong>Laravel Pint</strong></h3>
<p><strong>Publisher:</strong> Open Southeners</p>
<p><strong>Description:</strong> Integrates Laravel Pint into your VSCode projects for automatic code formatting</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=open-southeners.laravel-pint">Marketplace Link</a></p>
<h3 id="heading-chatgpt-a-work-with-code-on-macos"><strong>ChatGPT â Work with Code on macOS</strong></h3>
<p><strong>Publisher:</strong> OpenAI</p>
<p><strong>Description:</strong> Allows the ChatGPT desktop application to read and edit files open in Visual Studio Code. It requires the ChatGPT desktop app to function.</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=openai.chatgpt">Marketplace Link</a></p>
<h3 id="heading-laravel-jump-controller"><strong>laravel-jump-controller</strong></h3>
<p><strong>Publisher:</strong> pgl</p>
<p><strong>Description:</strong> Alt + click to navigate from a route to a respective controller file</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=pgl.laravel-jump-controller">Marketplace Link</a></p>
<h3 id="heading-material-icon-theme"><strong>Material Icon Theme</strong></h3>
<p><strong>Publisher:</strong> Philipp Kief</p>
<p><strong>Description:</strong> Material Design Icons for Visual Studio Code</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=pkief.material-icon-theme">Marketplace Link</a></p>
<h3 id="heading-toggle-case"><strong>Toggle Case</strong></h3>
<p><strong>Publisher:</strong> Pranshu Agrawal</p>
<p><strong>Description:</strong> Toggle through various cases on a key press</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=pranshuagrawal.toggle-case">Marketplace Link</a></p>
<h3 id="heading-xml"><strong>XML</strong></h3>
<p><strong>Publisher:</strong> Red Hat</p>
<p><strong>Description:</strong> XML Language Support by Red Hat</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=redhat.vscode-xml">Marketplace Link</a></p>
<h3 id="heading-yaml"><strong>YAML</strong></h3>
<p><strong>Publisher:</strong> Red Hat</p>
<p><strong>Description:</strong> YAML Language Support by Red Hat, with built-in Kubernetes syntax support</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml">Marketplace Link</a></p>
<h3 id="heading-live-server"><strong>Live Server</strong></h3>
<p><strong>Publisher:</strong> Ritwick Dey</p>
<p><strong>Description:</strong> Launch a development local Server with live reload feature for static &amp; dynamic pages</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=ritwickdey.liveserver">Marketplace Link</a></p>
<h3 id="heading-laravel-artisan"><strong>Laravel Artisan</strong></h3>
<p><strong>Publisher:</strong> Ryan Naddy</p>
<p><strong>Description:</strong> Run Laravel Artisan commands within Visual Studio Code</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=ryannaddy.laravel-artisan">Marketplace Link</a></p>
<h3 id="heading-git-merger"><strong>Git Merger</strong></h3>
<p><strong>Publisher:</strong> Shahar Kazaz</p>
<p><strong>Description:</strong> Simplifies the git merge process</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=shaharkazaz.git-merger">Marketplace Link</a></p>
<h3 id="heading-markdown-preview-enhanced"><strong>Markdown Preview Enhanced</strong></h3>
<p><strong>Publisher:</strong> Yiyi Wang</p>
<p><strong>Description:</strong> Markdown Preview Enhanced ported to vscode</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=shd101wyy.markdown-preview-enhanced">Marketplace Link</a></p>
<h3 id="heading-vue-helper"><strong>vue-helper</strong></h3>
<p><strong>Publisher:</strong> shenjiaolong</p>
<p><strong>Description:</strong> vue enhance, extension for Element-UI, Element Plus, Ant Desigin Vue</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=shenjiaolong.vue-helper">Marketplace Link</a></p>
<h3 id="heading-laravel-blade-formatter"><strong>Laravel Blade formatter</strong></h3>
<p><strong>Publisher:</strong> Shuhei Hayashibara</p>
<p><strong>Description:</strong> Laravel Blade formatter for VSCode</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=shufo.vscode-blade-formatter">Marketplace Link</a></p>
<h3 id="heading-rewrap"><strong>Rewrap</strong></h3>
<p><strong>Publisher:</strong> stkb</p>
<p><strong>Description:</strong> Hard word wrapping for comments and other text at a given column.</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=stkb.rewrap">Marketplace Link</a></p>
<h3 id="heading-code-spell-checker"><strong>Code Spell Checker</strong></h3>
<p><strong>Publisher:</strong> Street Side Software</p>
<p><strong>Description:</strong> Spelling checker for source code</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker">Marketplace Link</a></p>
<h3 id="heading-window-colors"><strong>Window Colors</strong></h3>
<p><strong>Publisher:</strong> Stuart Robinson</p>
<p><strong>Description:</strong> Automatically adds a unique color to each window's activityBar and titleBar.</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=stuart.unique-window-colors">Marketplace Link</a></p>
<h3 id="heading-vscode-pdf"><strong>vscode-pdf</strong></h3>
<p><strong>Publisher:</strong> tomoki1207</p>
<p><strong>Description:</strong> Display pdf file in VSCode.</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=tomoki1207.pdf">Marketplace Link</a></p>
<h3 id="heading-vue-official"><strong>Vue - Official</strong></h3>
<p><strong>Publisher:</strong> Vue</p>
<p><strong>Description:</strong> Language Support for Vue</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=vue.volar">Marketplace Link</a></p>
<h3 id="heading-git-blame"><strong>Git Blame</strong></h3>
<p><strong>Publisher:</strong> Wade Anderson</p>
<p><strong>Description:</strong> See git blame information in the status bar.</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=waderyan.gitblame">Marketplace Link</a></p>
<h3 id="heading-vscode-js-import"><strong>vscode-js-import</strong></h3>
<p><strong>Publisher:</strong> wangtao0101</p>
<p><strong>Description:</strong> Intelligent and fast import extension for js in vscode, support import position option and adding import to existing import statement.</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=wangtao0101.vscode-js-import">Marketplace Link</a></p>
<h3 id="heading-todo-highlight"><strong>TODO Highlight</strong></h3>
<p><strong>Publisher:</strong> Wayou Liu</p>
<p><strong>Description:</strong> highlight TODOs, FIXMEs, and any keywords, annotations...</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=wayou.vscode-todo-highlight">Marketplace Link</a></p>
<h3 id="heading-git-configure"><strong>git-configure</strong></h3>
<p><strong>Publisher:</strong> windsonR</p>
<p><strong>Description:</strong> In vscode, config GPG key to git config</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=windsonr.git-configure">Marketplace Link</a></p>
<h3 id="heading-javascript-es6-code-snippets"><strong>JavaScript (ES6) code snippets</strong></h3>
<p><strong>Publisher:</strong> charalampos karypidis</p>
<p><strong>Description:</strong> Code snippets for JavaScript in ES6 syntax</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=xabikos.javascriptsnippets">Marketplace Link</a></p>
<h3 id="heading-php-debug"><strong>PHP Debug</strong></h3>
<p><strong>Publisher:</strong> Xdebug</p>
<p><strong>Description:</strong> Debug support for PHP with Xdebug</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=xdebug.php-debug">Marketplace Link</a></p>
<h3 id="heading-vue-component"><strong>vue-component</strong></h3>
<p><strong>Publisher:</strong> zhubincong</p>
<p><strong>Description:</strong> Use vue components easily</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=zhubincong.vue-component">Marketplace Link</a></p>
<h3 id="heading-vue"><strong>Vue</strong></h3>
<p><strong>Publisher:</strong> Rahul Kadyan</p>
<p><strong>Description:</strong> Syntax Highlight</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=znck.vue">Marketplace Link</a></p>
<h3 id="heading-php-intellisense"><strong>PHP IntelliSense</strong></h3>
<p><strong>Publisher:</strong> Damjan Cvetko</p>
<p><strong>Description:</strong> Advanced Autocompletion and Refactoring support for PHP</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=zobo.php-intellisense">Marketplace Link</a></p>
<h2 id="heading-why-these-extensions-matter"><strong>Why These Extensions Matter</strong></h2>
<p>Each of these extensions has been carefully selected to address specific pain points in my development process. From code formatting and intellisense to version control and productivity tools, they work together to create a seamless and efficient coding environment.</p>
<p>Key benefits include:</p>
<ul>
<li><p>Enhanced code quality</p>
</li>
<li><p>Improved developer productivity</p>
</li>
<li><p>Simplified workflow</p>
</li>
<li><p>Better code navigation and understanding</p>
</li>
<li><p>Advanced debugging capabilities</p>
</li>
</ul>
<h2 id="heading-final-thoughts"><strong>Final Thoughts</strong></h2>
<p>Developing software is not just about writing code; it's about creating an environment that allows you to do your best work. These VSCode extensions are more than just tools—they're collaborative partners that help me write cleaner, more efficient code.</p>
<p><strong>Pro Tip:</strong> Remember that the perfect development setup is personal. What works for me might need tweaking to suit your specific workflow. Don't be afraid to experiment and find the extensions that resonate with your coding style.</p>
<p>Happy coding! 🚀👩‍💻👨‍💻</p>
]]></content:encoded></item><item><title><![CDATA[Building Your Cloud Home: A Step-by-Step Guide to AWS VPC Architecture]]></title><description><![CDATA[A Step-by-Step Guide to AWS VPC Architecture
What We're Building Today
Imagine being able to build your own digital neighborhood, complete with public areas, private spaces, and secure entrances - all perfectly organized for safety, efficiency, and g...]]></description><link>https://notes.sohag.pro/aws-vpc-architecture</link><guid isPermaLink="true">https://notes.sohag.pro/aws-vpc-architecture</guid><category><![CDATA[AWS]]></category><category><![CDATA[vpc]]></category><category><![CDATA[architecture]]></category><dc:creator><![CDATA[Sohag Hasan]]></dc:creator><pubDate>Tue, 18 Mar 2025 22:06:04 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1742334967006/82bd036d-4182-449c-bd1d-74859deb5212.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-a-step-by-step-guide-to-aws-vpc-architecture">A Step-by-Step Guide to AWS VPC Architecture</h1>
<h2 id="heading-what-were-building-today">What We're Building Today</h2>
<p>Imagine being able to build your own digital neighborhood, complete with public areas, private spaces, and secure entrances - all perfectly organized for safety, efficiency, and growth. That's exactly what we'll be doing in AWS today!</p>
<p>By the end of this tutorial, you will have created:</p>
<ul>
<li><p>A secure, isolated cloud network (VPC)</p>
</li>
<li><p>Public and private areas (subnets) in different locations (availability zones)</p>
</li>
<li><p>Safe entrances and exits to the internet (gateways)</p>
</li>
<li><p>Traffic rules to keep everything running smoothly (route tables)</p>
</li>
</ul>
<p>Whether you're just starting your cloud journey or looking to strengthen your AWS fundamentals, this guide will walk you through creating a production-ready network architecture using simple, everyday analogies.</p>
<h2 id="heading-why-do-we-need-this">Why Do We Need This?</h2>
<p>Before we start building, let's understand why this matters:</p>
<ol>
<li><p><strong>Security</strong>: Just like you wouldn't want strangers wandering through your bedroom, some parts of your application (like databases) should be kept private.</p>
</li>
<li><p><strong>Reliability</strong>: If one neighborhood (availability zone) experiences a power outage, your application can still run in another neighborhood.</p>
</li>
<li><p><strong>Organization</strong>: Good fences make good neighbors! Properly separating your resources makes them easier to manage.</p>
</li>
<li><p><strong>Scalability</strong>: A well-planned network gives your applications room to grow.</p>
</li>
</ol>
<p>Now, let's start building our cloud neighborhood!</p>
<h2 id="heading-step-1-creating-your-vpc-your-digital-property">Step 1: Creating Your VPC (Your Digital Property)</h2>
<p>Think of a VPC as buying a large plot of land where you'll build your digital home. You need to decide how big it should be and establish the boundaries.</p>
<p><strong>Here's what to do:</strong></p>
<ol>
<li><p>Sign in to the AWS Management Console</p>
</li>
<li><p>Navigate to "VPC" under Services</p>
</li>
<li><p>Click "Create VPC"</p>
</li>
<li><p>Fill in these details:</p>
<ul>
<li><p>Name: <code>MyDigitalNeighborhood</code></p>
</li>
<li><p>IPv4 CIDR block: <code>10.0.0.0/16</code></p>
</li>
<li><p>Leave other settings as default</p>
</li>
</ul>
</li>
<li><p>Click "Create VPC"</p>
</li>
</ol>
<h2 id="heading-understanding-cidr-the-magic-behind-ip-addressing">Understanding CIDR: The Magic Behind IP Addressing</h2>
<p>Imagine the internet as a giant city with billions of houses (computers), and each house needs a unique address (IP address). CIDR (Classless Inter-Domain Routing) is the clever system we use to organize these addresses.</p>
<h3 id="heading-what-the-numbers-mean">What the Numbers Mean</h3>
<p>The CIDR notation like <code>10.0.0.0/16</code> has two important parts:</p>
<ul>
<li><p>The first part (<code>10.0.0.0</code>) is the starting address of your neighborhood</p>
</li>
<li><p>The second part (<code>/16</code>) tells us how many addresses belong to you</p>
</li>
</ul>
<p>The number after the slash (<code>/16</code>) represents how many bits in the IP address are fixed for your network. An IP address has 32 bits total, so:</p>
<ul>
<li><p><code>/16</code> means 16 bits are fixed, leaving 16 bits for your addresses (2^16 = 65,536 addresses)</p>
</li>
<li><p><code>/24</code> means 24 bits are fixed, leaving only 8 bits for your addresses (2^8 = 256 addresses)</p>
</li>
<li><p><code>/28</code> means 28 bits are fixed, leaving just 4 bits for your addresses (2^4 = 16 addresses)</p>
</li>
</ul>
<h3 id="heading-how-to-calculate-available-addresses">How to Calculate Available Addresses</h3>
<p>Here's a simple way to calculate how many addresses you get:</p>
<ol>
<li><p>Take the number after the slash (let's call it N)</p>
</li>
<li><p>Subtract it from 32 (32 - N)</p>
</li>
<li><p>Raise 2 to that power: 2^(32-N)</p>
</li>
</ol>
<p>Examples:</p>
<ul>
<li><p>For <code>/16</code>: 2^(32-16) = 2^16 = 65,536 addresses</p>
</li>
<li><p>For <code>/24</code>: 2^(32-24) = 2^8 = 256 addresses</p>
</li>
<li><p>For <code>/28</code>: 2^(32-28) = 2^4 = 16 addresses</p>
</li>
</ul>
<h3 id="heading-address-range-calculation">Address Range Calculation</h3>
<p>To find the range of addresses in a CIDR block:</p>
<ul>
<li><p>Starting address: The address you specified (e.g., <code>10.0.0.0</code>)</p>
</li>
<li><p>Ending address: Add your total number of addresses to the starting address, then subtract 1</p>
</li>
</ul>
<p>For <code>10.0.0.0/16</code>:</p>
<ul>
<li><p>Starting: <code>10.0.0.0</code></p>
</li>
<li><p>Ending: <code>10.0.0.0</code> + 65,536 - 1 = <code>10.0.255.255</code></p>
</li>
</ul>
<p>For <code>10.0.1.0/24</code>:</p>
<ul>
<li><p>Starting: <code>10.0.1.0</code></p>
</li>
<li><p>Ending: <code>10.0.1.0</code> + 256 - 1 = <code>10.0.1.255</code></p>
</li>
</ul>
<h3 id="heading-practical-tips-for-cidr-planning">Practical Tips for CIDR Planning</h3>
<ol>
<li><p><strong>Start Bigger Than You Need</strong>: It's easier to subnet a large network than to expand a small one. Begin with a <code>/16</code> for your VPC if possible.</p>
</li>
<li><p><strong>Use Powers of 2</strong>: Always create subnets with sizes that are powers of 2 (256, 512, 1024, etc.). This keeps your CIDR math clean.</p>
</li>
<li><p><strong>Mind Your Zeros</strong>: When creating a subnet, make sure the network address ends with the right number of zeros. For example, a <code>/24</code> network must end with one zero (like <code>10.0.1.0</code>).</p>
</li>
<li><p><strong>Leave Room for Growth</strong>: Don't make your subnets too small. If you think you need 100 addresses, use a <code>/24</code> (256 addresses) rather than a <code>/25</code> (128 addresses).</p>
</li>
<li><p><strong>CIDR Cheat Sheet</strong>:</p>
<ul>
<li><p><code>/16</code> = 65,536 addresses (large VPC)</p>
</li>
<li><p><code>/20</code> = 4,096 addresses (medium subnet)</p>
</li>
<li><p><code>/24</code> = 256 addresses (standard subnet)</p>
</li>
<li><p><code>/28</code> = 16 addresses (small subnet)</p>
</li>
<li><p><code>/32</code> = 1 address (single IP)</p>
</li>
</ul>
</li>
</ol>
<p>Think of CIDR like buying land: the smaller the number after the slash, the larger your property! A <code>/16</code> is like owning a whole county, while a <code>/24</code> is more like owning a city block.</p>
<h2 id="heading-step-2-creating-subnets-neighborhoods-within-your-property">Step 2: Creating Subnets (Neighborhoods within Your Property)</h2>
<p>Now that we have our land, let's divide it into different areas - some public (like front yards) and some private (like backyards). And we'll create these areas in different locations (availability zones) for safety.</p>
<p><strong>Here's what to do:</strong></p>
<h3 id="heading-public-subnet-in-first-location-az-1">Public Subnet in First Location (AZ-1)</h3>
<ol>
<li><p>In the VPC Dashboard, click "Subnets"</p>
</li>
<li><p>Click "Create subnet"</p>
</li>
<li><p>Configure:</p>
<ul>
<li><p>VPC: Select your <code>MyDigitalNeighborhood</code></p>
</li>
<li><p>Name: <code>FrontYard-East</code></p>
</li>
<li><p>Availability Zone: Select the first AZ (e.g., us-east-1a)</p>
</li>
<li><p>CIDR block: <code>10.0.1.0/24</code></p>
</li>
</ul>
</li>
<li><p>Click "Create"</p>
</li>
</ol>
<h3 id="heading-private-subnet-in-first-location-az-1">Private Subnet in First Location (AZ-1)</h3>
<ol>
<li><p>Click "Create subnet" again</p>
</li>
<li><p>Configure:</p>
<ul>
<li><p>VPC: Same VPC</p>
</li>
<li><p>Name: <code>BackYard-East</code></p>
</li>
<li><p>Availability Zone: Same as above (e.g., us-east-1a)</p>
</li>
<li><p>CIDR block: <code>10.0.2.0/24</code></p>
</li>
</ul>
</li>
<li><p>Click "Create"</p>
</li>
</ol>
<h3 id="heading-public-subnet-in-second-location-az-2">Public Subnet in Second Location (AZ-2)</h3>
<ol>
<li><p>Click "Create subnet" again</p>
</li>
<li><p>Configure:</p>
<ul>
<li><p>VPC: Same VPC</p>
</li>
<li><p>Name: <code>FrontYard-West</code></p>
</li>
<li><p>Availability Zone: Select a different AZ (e.g., us-east-1b)</p>
</li>
<li><p>CIDR block: <code>10.0.3.0/24</code></p>
</li>
</ul>
</li>
<li><p>Click "Create"</p>
</li>
</ol>
<h3 id="heading-private-subnet-in-second-location-az-2">Private Subnet in Second Location (AZ-2)</h3>
<ol>
<li><p>Click "Create subnet" again</p>
</li>
<li><p>Configure:</p>
<ul>
<li><p>VPC: Same VPC</p>
</li>
<li><p>Name: <code>BackYard-West</code></p>
</li>
<li><p>Availability Zone: Same as above (e.g., us-east-1b)</p>
</li>
<li><p>CIDR block: <code>10.0.4.0/24</code></p>
</li>
</ul>
</li>
<li><p>Click "Create"</p>
</li>
</ol>
<p><strong>Why We Did It This Way:</strong></p>
<p>Think of this like building a house with front yards (public subnets) and backyards (private subnets) in two different neighborhoods (availability zones).</p>
<ul>
<li><p><strong>Front yards</strong> (public subnets) are visible from the street and accessible to visitors</p>
</li>
<li><p><strong>Backyards</strong> (private subnets) are more secure and not directly accessible from the street</p>
</li>
<li><p>Building in <strong>two neighborhoods</strong> (AZs) means if one has a problem (like a power outage), you can still use the other</p>
</li>
</ul>
<h2 id="heading-step-3-creating-an-internet-gateway-your-main-entrance">Step 3: Creating an Internet Gateway (Your Main Entrance)</h2>
<p>Now we need a way for people to enter and exit our property from the main road (internet). This is our Internet Gateway.</p>
<p><strong>Here's what to do:</strong></p>
<ol>
<li><p>In the VPC Dashboard, click "Internet Gateways"</p>
</li>
<li><p>Click "Create internet gateway"</p>
</li>
<li><p>Name it <code>MainEntrance</code></p>
</li>
<li><p>Click "Create"</p>
</li>
<li><p>Select your new gateway and click "Actions" &gt; "Attach to VPC"</p>
</li>
<li><p>Select your VPC and click "Attach"</p>
</li>
</ol>
<p><strong>Why We Need This:</strong></p>
<p>Just like your house needs a front door to let people in and out, your VPC needs an Internet Gateway to allow traffic between your resources and the internet. Without it, your public resources would be isolated from the outside world!</p>
<h2 id="heading-step-4-creating-a-nat-gateway-your-service-entrance">Step 4: Creating a NAT Gateway (Your Service Entrance)</h2>
<p>Now, things in our backyard (private subnets) need a way to access the internet for updates and downloads, but we don't want strangers coming in through this door. That's what a NAT Gateway is for.</p>
<p><strong>Here's what to do:</strong></p>
<ol>
<li><p>In the VPC Dashboard, click "NAT Gateways"</p>
</li>
<li><p>Click "Create NAT gateway"</p>
</li>
<li><p>Configure:</p>
<ul>
<li><p>Name: <code>ServiceEntrance</code></p>
</li>
<li><p>Subnet: Select one of your public subnets (e.g., <code>FrontYard-East</code>)</p>
</li>
<li><p>Connectivity: Public</p>
</li>
<li><p>Elastic IP: Click "Allocate Elastic IP"</p>
</li>
</ul>
</li>
<li><p>Click "Create NAT gateway"</p>
</li>
</ol>
<p><strong>Why We Need This:</strong></p>
<p>Imagine your private backyard has plants that need water (updates from the internet). The NAT Gateway is like a gardener who can go out to get water and bring it back, but strangers can't use this entrance to come in uninvited. This way, your private resources can access the internet without being exposed to it.</p>
<h2 id="heading-step-5-setting-up-route-tables-traffic-rules">Step 5: Setting Up Route Tables (Traffic Rules)</h2>
<p>Now we need to create rules about how traffic should flow in our neighborhoods.</p>
<h3 id="heading-public-route-table-rules-for-front-yards">Public Route Table (Rules for Front Yards)</h3>
<ol>
<li><p>Go to "Route Tables" in the VPC Dashboard</p>
</li>
<li><p>Click "Create route table"</p>
</li>
<li><p>Configure:</p>
<ul>
<li><p>Name: <code>FrontYard-Rules</code></p>
</li>
<li><p>VPC: Your VPC</p>
</li>
</ul>
</li>
<li><p>Click "Create"</p>
</li>
<li><p>Select the new route table</p>
</li>
<li><p>Go to "Routes" tab and click "Edit routes"</p>
</li>
<li><p>Click "Add route"</p>
<ul>
<li><p>Destination: <code>0.0.0.0/0</code> (everywhere on the internet)</p>
</li>
<li><p>Target: Select your Internet Gateway</p>
</li>
</ul>
</li>
<li><p>Click "Save changes"</p>
</li>
<li><p>Go to "Subnet associations" tab</p>
</li>
<li><p>Click "Edit subnet associations"</p>
</li>
<li><p>Select both your public subnets (<code>FrontYard-East</code> and <code>FrontYard-West</code>)</p>
</li>
<li><p>Click "Save associations"</p>
</li>
</ol>
<h3 id="heading-private-route-table-rules-for-back-yards">Private Route Table (Rules for Back Yards)</h3>
<ol>
<li><p>Click "Create route table" again</p>
</li>
<li><p>Configure:</p>
<ul>
<li><p>Name: <code>BackYard-Rules</code></p>
</li>
<li><p>VPC: Your VPC</p>
</li>
</ul>
</li>
<li><p>Click "Create"</p>
</li>
<li><p>Select this new route table</p>
</li>
<li><p>Go to "Routes" tab and click "Edit routes"</p>
</li>
<li><p>Click "Add route"</p>
<ul>
<li><p>Destination: <code>0.0.0.0/0</code> (everywhere on the internet)</p>
</li>
<li><p>Target: Select your NAT Gateway</p>
</li>
</ul>
</li>
<li><p>Click "Save changes"</p>
</li>
<li><p>Go to "Subnet associations" tab</p>
</li>
<li><p>Click "Edit subnet associations"</p>
</li>
<li><p>Select both your private subnets (<code>BackYard-East</code> and <code>BackYard-West</code>)</p>
</li>
<li><p>Click "Save associations"</p>
</li>
</ol>
<p><strong>Why We Did It This Way:</strong></p>
<p>Think of route tables like giving directions to visitors:</p>
<ul>
<li><p>The public route table says: "To get to the internet, use the main entrance (Internet Gateway)"</p>
</li>
<li><p>The private route table says: "To get to the internet, use the service entrance (NAT Gateway)"</p>
</li>
</ul>
<p>This ensures traffic flows exactly how we want it to: public resources can communicate directly with the internet, while private resources can only send requests out through the NAT Gateway.</p>
<h2 id="heading-step-6-enabling-auto-assign-public-ip-for-public-subnets">Step 6: Enabling Auto-assign Public IP for Public Subnets</h2>
<p>Our front yards need addresses that are visible from the street.</p>
<p><strong>Here's what to do:</strong></p>
<ol>
<li><p>Go to "Subnets" in the VPC Dashboard</p>
</li>
<li><p>Select your first public subnet (<code>FrontYard-East</code>)</p>
</li>
<li><p>Click "Actions" &gt; "Edit subnet settings"</p>
</li>
<li><p>Check "Enable auto-assign public IPv4 address"</p>
</li>
<li><p>Click "Save"</p>
</li>
<li><p>Repeat for your second public subnet (<code>FrontYard-West</code>)</p>
</li>
</ol>
<p><strong>Why We Need This:</strong></p>
<p>This is like putting a house number on your mailbox so people can find you. Without a public IP address, resources in your public subnets wouldn't be reachable from the internet.</p>
<h2 id="heading-what-weve-built-the-big-picture">What We've Built: The Big Picture</h2>
<p>Congratulations! You've now built a complete cloud network architecture. Let's review what we have:</p>
<ol>
<li><p><strong>A VPC</strong> (<code>10.0.0.0/16</code>): Your digital property with 65,536 possible addresses</p>
</li>
<li><p><strong>Four Subnets</strong>:</p>
<ul>
<li><p>Two public "front yards" (<code>10.0.1.0/24</code> and <code>10.0.3.0/24</code>)</p>
</li>
<li><p>Two private "back yards" (<code>10.0.2.0/24</code> and <code>10.0.4.0/24</code>)</p>
</li>
<li><p>Located in two different neighborhoods (availability zones)</p>
</li>
</ul>
</li>
<li><p><strong>Gateways</strong>:</p>
<ul>
<li><p>An Internet Gateway (main entrance)</p>
</li>
<li><p>A NAT Gateway (service entrance)</p>
</li>
</ul>
</li>
<li><p><strong>Route Tables</strong>:</p>
<ul>
<li><p>Public routes for front yards</p>
</li>
<li><p>Private routes for back yards</p>
</li>
</ul>
</li>
</ol>
<h2 id="heading-real-world-application">Real-World Application</h2>
<p>Now that our cloud neighborhood is built, here's how you might use it:</p>
<ul>
<li><p><strong>Public Subnets</strong> (Front Yards): Place web servers, load balancers, and public-facing applications here</p>
</li>
<li><p><strong>Private Subnets</strong> (Back Yards): Place databases, application servers, and other sensitive resources here</p>
</li>
<li><p><strong>Multiple AZs</strong> (Different Neighborhoods): Ensures your application stays running even if one area has problems</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Building a VPC architecture might seem complicated at first, but when you break it down into simple concepts like yards, entrances, and traffic rules, it becomes much clearer.</p>
<p>This architecture follows AWS best practices and gives you a solid foundation for hosting applications securely in the cloud. As your needs grow, you can expand this architecture by adding more subnets or connecting to other VPCs.</p>
<p>Remember: in the cloud, good fences (network boundaries) really do make good neighbors (secure applications)!</p>
<p>Now go ahead and start placing your resources in your new cloud home. Your web servers will enjoy the view from the front yard, while your databases can relax securely in the backyard!</p>
]]></content:encoded></item><item><title><![CDATA[Decoding AWS Network Lingo: A Beginner's Guide to VPCs, Subnets, and Gateways]]></title><description><![CDATA[What are these VPCs, Subnets, and Gateways?
Have you ever felt overwhelmed by the alphabet soup of AWS networking terms? You're not alone! As a cloud newcomer, understanding terms like VPC, CIDR, and NAT Gateway can feel like learning a foreign langu...]]></description><link>https://notes.sohag.pro/vpcs-subnets-and-gateways</link><guid isPermaLink="true">https://notes.sohag.pro/vpcs-subnets-and-gateways</guid><category><![CDATA[AWS]]></category><category><![CDATA[networking]]></category><category><![CDATA[architecture]]></category><dc:creator><![CDATA[Sohag Hasan]]></dc:creator><pubDate>Tue, 18 Mar 2025 21:44:29 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1742334170286/24392429-b25a-434a-a13f-d470b7c78fc2.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-what-are-these-vpcs-subnets-and-gateways">What are these VPCs, Subnets, and Gateways?</h1>
<p>Have you ever felt overwhelmed by the alphabet soup of AWS networking terms? You're not alone! As a cloud newcomer, understanding terms like VPC, CIDR, and NAT Gateway can feel like learning a foreign language. In this beginner-friendly guide, I'll break down these intimidating acronyms into simple concepts you can relate to in everyday life.</p>
<h2 id="heading-vpc-virtual-private-cloud">VPC (Virtual Private Cloud)</h2>
<p><strong>What it is:</strong> A VPC is your own private section of the AWS cloud where you can place your resources (like servers and databases).</p>
<p><strong>Real-life analogy:</strong> Think of a VPC as your own private property or gated community. Just like you'd build different structures on your property (house, garage, garden shed), you can place different AWS resources in your VPC. And just as you decide who can enter your property, you control who can access your VPC.</p>
<p><strong>Why it matters:</strong> VPCs isolate your resources from other AWS customers, providing security and organization. You get to define your own network rules, just like you would set house rules for your home.</p>
<h2 id="heading-cidr-classless-inter-domain-routing">CIDR (Classless Inter-Domain Routing)</h2>
<p><strong>What it is:</strong> CIDR is a method for allocating IP addresses and routing network traffic.</p>
<p><strong>Real-life analogy:</strong> Imagine a postal system where CIDR is like zip codes. Just as zip codes help organize mail delivery to specific areas, CIDR blocks help organize network traffic to specific parts of your cloud infrastructure.</p>
<p><strong>Example:</strong> A CIDR notation like <code>10.0.0.0/16</code> means you have addresses ranging from 10.0.0.0 to 10.0.255.255 – that's 65,536 IP addresses! A smaller block like <code>10.0.1.0/24</code> gives you 256 addresses.</p>
<p><strong>Why it matters:</strong> CIDR helps you organize your network logically and ensures you have enough IP addresses for your needs without wasting them.</p>
<h2 id="heading-az-availability-zone">AZ (Availability Zone)</h2>
<p><strong>What it is:</strong> An isolated location within an AWS Region that contains data centers.</p>
<p><strong>Real-life analogy:</strong> Think of AZs as separate power grids in a city. If one power grid fails due to a storm, the others can continue operating independently. Similarly, if one AZ has issues, your applications in other AZs can continue running.</p>
<p><strong>Why it matters:</strong> Using multiple AZs protects your applications from outages in a single location – it's like not putting all your eggs in one basket.</p>
<h2 id="heading-subnet">Subnet</h2>
<p><strong>What it is:</strong> A subnet is a segment of a VPC's IP address range where you can place groups of resources.</p>
<p><strong>Real-life analogy:</strong> If your VPC is a large office building, subnets are like different departments or floors. You might have the HR department on one floor, engineering on another, and marketing on a third.</p>
<p><strong>Example:</strong> In our VPC with CIDR <code>10.0.0.0/16</code>, we might create subnets like:</p>
<ul>
<li><p>Marketing department: <code>10.0.1.0/24</code> (256 addresses)</p>
</li>
<li><p>Engineering department: <code>10.0.2.0/24</code> (256 addresses)</p>
</li>
</ul>
<p><strong>Why it matters:</strong> Subnets help organize your resources and apply different security rules to different groups of resources.</p>
<h2 id="heading-public-vs-private-subnets">Public vs. Private Subnets</h2>
<p><strong>What they are:</strong> Public subnets can send and receive traffic directly from the internet, while private subnets cannot.</p>
<p><strong>Real-life analogy:</strong> Public subnets are like the reception area of a building – accessible to visitors from outside. Private subnets are like secure back offices that only employees can access.</p>
<p><strong>Why they matter:</strong> This separation helps maintain security. You keep customer-facing applications in public subnets while keeping sensitive data and backend systems in private subnets.</p>
<h2 id="heading-igw-internet-gateway">IGW (Internet Gateway)</h2>
<p><strong>What it is:</strong> An IGW allows resources in your VPC to connect to the internet.</p>
<p><strong>Real-life analogy:</strong> An IGW is like the main entrance and exit of your building. It's the doorway through which people (or data) can come in from the public street (internet) or go out to it.</p>
<p><strong>Why it matters:</strong> Without an IGW, resources in your VPC would be isolated from the internet – like a building with no doors to the outside world.</p>
<h2 id="heading-nat-network-address-translation-gateway">NAT (Network Address Translation) Gateway</h2>
<p><strong>What it is:</strong> A NAT Gateway allows resources in private subnets to access the internet while preventing the internet from initiating connections to those resources.</p>
<p><strong>Real-life analogy:</strong> A NAT Gateway is like a security guard at a service entrance. Employees can go out to run errands (access the internet), but random people can't enter through this door (the internet can't initiate connections).</p>
<p><strong>Example:</strong> Your database server in a private subnet needs to download updates. The NAT Gateway allows it to access the download server on the internet, but doesn't allow external users to connect directly to your database.</p>
<p><strong>Why it matters:</strong> NAT Gateways provide a secure way for private resources to access the internet without exposing them to potential attacks.</p>
<h2 id="heading-route-table">Route Table</h2>
<p><strong>What it is:</strong> A route table contains a set of rules (routes) that determine where network traffic is directed.</p>
<p><strong>Real-life analogy:</strong> Think of a route table as a GPS navigation system that tells data packets which way to go to reach their destination.</p>
<p><strong>Example:</strong> Your route table might say "to reach the internet, go through the IGW" or "to reach this private subnet, go this way."</p>
<p><strong>Why it matters:</strong> Route tables ensure your network traffic flows the right way, just like road signs ensure drivers take the correct routes.</p>
<h2 id="heading-elastic-ip">Elastic IP</h2>
<p><strong>What it is:</strong> A static, public IPv4 address that you can allocate to your AWS account and associate with resources.</p>
<p><strong>Real-life analogy:</strong> An Elastic IP is like a permanent phone number that stays the same even if you change phones. Even if your underlying AWS resources change, the Elastic IP remains constant.</p>
<p><strong>Why it matters:</strong> When you need a fixed address for your resources (like a website domain pointing to your server), an Elastic IP ensures it doesn't change.</p>
<h2 id="heading-putting-it-all-together">Putting It All Together</h2>
<p>Imagine you're building a simple e-commerce website:</p>
<ol>
<li><p>You create a <strong>VPC</strong> (your digital property) with a <strong>CIDR</strong> block of <code>10.0.0.0/16</code>.</p>
</li>
<li><p>You create <strong>subnets</strong> in multiple <strong>AZs</strong> for redundancy:</p>
<ul>
<li><p>Public subnets for your web servers</p>
</li>
<li><p>Private subnets for your database and application servers</p>
</li>
</ul>
</li>
<li><p>You attach an <strong>IGW</strong> to your VPC so your web servers can serve content to your customers.</p>
</li>
<li><p>You set up a <strong>NAT Gateway</strong> so your private resources can download updates.</p>
</li>
<li><p>You configure <strong>route tables</strong> to direct traffic appropriately:</p>
<ul>
<li><p>Public subnets route internet traffic through the IGW</p>
</li>
<li><p>Private subnets route internet traffic through the NAT Gateway</p>
</li>
</ul>
</li>
</ol>
<p>This setup ensures your website is both accessible to customers and secure from attacks.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Understanding AWS networking terms doesn't have to be complicated. By relating these concepts to everyday objects and situations, you can build a mental model that makes cloud networking more approachable. As you continue your AWS journey, you'll become more comfortable with these terms and how they work together to create secure, reliable network architectures.</p>
<p>Remember, even AWS experts started as beginners. Take it one acronym at a time, and soon you'll be speaking AWS networking fluently!</p>
]]></content:encoded></item><item><title><![CDATA[Laravel Meets AWS ECS: Automate Deployments Like a CI/CD Ninja!]]></title><description><![CDATA[Setting Up a CI/CD Pipeline for Laravel Applications with AWS ECS
In today's fast-paced development environment, implementing a robust Continuous Integration and Continuous Deployment (CI/CD) pipeline is essential for delivering high-quality applicat...]]></description><link>https://notes.sohag.pro/laravel-aws-ecs-automated-ci-cd-deployment</link><guid isPermaLink="true">https://notes.sohag.pro/laravel-aws-ecs-automated-ci-cd-deployment</guid><category><![CDATA[AWS]]></category><category><![CDATA[AWS ECS Fargate]]></category><category><![CDATA[Laravel]]></category><dc:creator><![CDATA[Sohag Hasan]]></dc:creator><pubDate>Wed, 12 Mar 2025 21:32:26 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1741814584947/8b3df2d6-bd45-4473-9a01-818a6623fbf1.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-setting-up-a-cicd-pipeline-for-laravel-applications-with-aws-ecs">Setting Up a CI/CD Pipeline for Laravel Applications with AWS ECS</h1>
<p>In today's fast-paced development environment, implementing a robust Continuous Integration and Continuous Deployment (CI/CD) pipeline is essential for delivering high-quality applications efficiently. This comprehensive guide will walk you through setting up a complete CI/CD pipeline for deploying Laravel applications on Amazon's Elastic Container Service (ECS).</p>
<h2 id="heading-tldr"><strong>TL;DR:</strong></h2>
<p>This guide walks you through setting up a <strong>CI/CD pipeline</strong> for deploying <strong>Laravel applications</strong> on <strong>AWS ECS</strong> using <strong>GitHub Actions</strong>. The pipeline automates code deployment by:</p>
<ol>
<li><p><strong>Pushing Code</strong> → Triggers GitHub Actions</p>
</li>
<li><p><strong>Building a Docker Image</strong> → Pushed to Amazon ECR</p>
</li>
<li><p><strong>Registering a New ECS Task</strong> → Updates the ECS service</p>
</li>
<li><p><strong>Deploying via Load Balancer</strong> → Ensuring High Availability</p>
</li>
</ol>
<p>It covers <strong>AWS setup</strong>, including IAM roles, Secrets Manager, ECR, ECS clusters, load balancers, and auto-scaling. Finally, it includes <strong>Dockerfile and Nginx configuration</strong> for Laravel deployment. 🚀</p>
<h2 id="heading-what-is-aws-ecs-and-ecr">What is AWS ECS and ECR?</h2>
<p>Before diving into how to use AWS ECS and ECR for deploying Laravel applications, it's essential to understand what these services are and how they work together in the AWS ecosystem.</p>
<h3 id="heading-amazon-elastic-container-service-ecs"><strong>Amazon Elastic Container Service (ECS)</strong></h3>
<p>Amazon ECS is a fully managed container orchestration service that helps you run and scale Docker containers on AWS. It allows you to easily deploy, manage, and scale containerized applications using a highly reliable and scalable infrastructure. ECS handles the scheduling of containers across a cluster of EC2 instances (or using Fargate for serverless containers) and automates many operational tasks, making it an ideal choice for managing microservices, batch jobs, and other containerized workloads.</p>
<p>ECS provides:</p>
<ul>
<li><p><strong>Container orchestration</strong>: Manage and scale Docker containers in a cluster of EC2 instances.</p>
</li>
<li><p><strong>Task definitions</strong>: Define the application specifications such as Docker images, networking configurations, and resource requirements.</p>
</li>
<li><p><strong>Cluster management</strong>: ECS abstracts the underlying infrastructure, making it easy to manage containers and resources.</p>
</li>
</ul>
<p>With ECS, you can easily automate deployment pipelines, ensure scalability, and manage the lifecycle of your application in a cloud-native way.</p>
<h3 id="heading-amazon-elastic-container-registry-ecr"><strong>Amazon Elastic Container Registry (ECR)</strong></h3>
<p>Amazon ECR is a fully managed Docker container registry that allows you to store, manage, and deploy Docker container images. It integrates seamlessly with ECS, simplifying the process of storing and retrieving container images during deployment. ECR eliminates the need to manage your own container registry infrastructure and provides built-in security and scalability features, making it easier to manage containerized applications.</p>
<p>Key benefits of ECR include:</p>
<ul>
<li><p><strong>Fully managed</strong>: ECR handles all aspects of container image storage, including scaling and security.</p>
</li>
<li><p><strong>Secure storage</strong>: Supports encryption of your images and integrates with AWS Identity and Access Management (IAM) for access control.</p>
</li>
<li><p><strong>Fast and reliable</strong>: Optimized for fast image pulls, ensuring that your deployment process is smooth and efficient.</p>
</li>
<li><p><strong>Integration with ECS and other AWS services</strong>: ECR is designed to work seamlessly with ECS, making it easier to deploy and manage your containers.</p>
</li>
</ul>
<p>In short, ECR allows you to store Docker images securely and make them accessible for deployment, while ECS manages the deployment, scaling, and orchestration of these containerized applications.</p>
<p>By using ECS and ECR together, you can automate the entire lifecycle of containerized applications—from building Docker images to deploying them with a fully managed infrastructure, all within the AWS cloud.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before we begin, ensure you have the following:</p>
<ul>
<li><p>An AWS account</p>
</li>
<li><p>A GitHub repository with your Laravel application</p>
</li>
<li><p>Basic understanding of Docker, Laravel, and AWS services</p>
</li>
<li><p>AWS CLI installed on your local machine</p>
</li>
<li><p>GitHub account with access to GitHub Actions</p>
</li>
</ul>
<h2 id="heading-architecture-overview">Architecture Overview</h2>
<p>Our CI/CD pipeline will follow this workflow:</p>
<ol>
<li><p>Developer pushes code to the GitHub repository</p>
</li>
<li><p>GitHub Actions workflow is triggered</p>
</li>
<li><p>The workflow builds a Docker image for the Laravel application</p>
</li>
<li><p>The image is pushed to Amazon ECR</p>
</li>
<li><p>A new ECS task definition is registered with the updated image</p>
</li>
<li><p>The ECS service is updated to use the new task definition</p>
</li>
<li><p>The application is deployed through a load balancer for high availability</p>
</li>
</ol>
<h2 id="heading-setting-up-aws-infrastructure">Setting Up AWS Infrastructure</h2>
<h3 id="heading-creating-an-iam-user-with-required-permissions">Creating an IAM User with Required Permissions</h3>
<p>First, let's create an IAM user with the necessary permissions for our CI/CD pipeline:</p>
<ol>
<li><p>Navigate to the IAM console in your AWS account</p>
</li>
<li><p>Click on "Users" and then "Create user"</p>
</li>
<li><p>Enter a name for your user (e.g., "laravel-ecs-cicd-user")</p>
</li>
<li><p>Click "Next: Permissions"</p>
</li>
<li><p>Select "Attach existing policies directly"</p>
</li>
<li><p>Search and select the following policies:</p>
<ul>
<li><p>AmazonEC2ContainerRegistryFullAccess</p>
</li>
<li><p>AmazonECS_FullAccess</p>
</li>
<li><p>AmazonECSTaskExecutionRolePolicy</p>
</li>
<li><p>SecretsManagerReadWrite</p>
</li>
</ul>
</li>
<li><p>Click "Next: Tags" (add tags if needed)</p>
</li>
<li><p>Click "Next: Review"</p>
</li>
<li><p>Click <strong>“Create User”</strong> to initiate user creation.</p>
</li>
<li><p>Navigate back to the <strong>Users List</strong> and select the newly created user.</p>
</li>
<li><p>Open the <strong>Security Credentials</strong> tab.</p>
</li>
<li><p>Scroll down to the <strong>Access Keys</strong> section and click <strong>“Create Access Key.”</strong></p>
</li>
<li><p>Copy and securely store the generated access keys, as they will not be displayed again.</p>
</li>
</ol>
<h3 id="heading-setting-up-aws-secrets-manager">Setting Up AWS Secrets Manager</h3>
<p>Next, let's store our Laravel environment variables securely in AWS Secrets Manager:</p>
<ol>
<li><p>Navigate to the AWS Secrets Manager console</p>
</li>
<li><p>Click "Store a new secret"</p>
</li>
<li><p>Select "Other type of secrets"</p>
</li>
<li><p>Enter your Laravel environment variables as key-value pairs JSON format (You can convert using ChatGPT):</p>
<pre><code class="lang-json"> {
   <span class="hljs-attr">"APP_NAME"</span>: <span class="hljs-string">"Laravel"</span>,
   <span class="hljs-attr">"APP_ENV"</span>: <span class="hljs-string">"local"</span>,
   <span class="hljs-attr">"APP_KEY"</span>: <span class="hljs-string">"base64:aWOTx31pPGbitApUzF6luBpFRtBxbLQHjardLfZKYTE="</span>,
   <span class="hljs-attr">"APP_DEBUG"</span>: <span class="hljs-string">"true"</span>,
   <span class="hljs-attr">"APP_TIMEZONE"</span>: <span class="hljs-string">"UTC"</span>,
   <span class="hljs-attr">"APP_URL"</span>: <span class="hljs-string">"http://localhost"</span>,
   <span class="hljs-attr">"APP_LOCALE"</span>: <span class="hljs-string">"en"</span>,
   <span class="hljs-attr">"APP_FALLBACK_LOCALE"</span>: <span class="hljs-string">"en"</span>,
   <span class="hljs-attr">"APP_FAKER_LOCALE"</span>: <span class="hljs-string">"en_US"</span>,
   <span class="hljs-attr">"APP_MAINTENANCE_DRIVER"</span>: <span class="hljs-string">"file"</span>,
   <span class="hljs-attr">"BCRYPT_ROUNDS"</span>: <span class="hljs-string">"12"</span>,
   <span class="hljs-attr">"LOG_CHANNEL"</span>: <span class="hljs-string">"stack"</span>,
   <span class="hljs-attr">"LOG_STACK"</span>: <span class="hljs-string">"single"</span>,
   <span class="hljs-attr">"LOG_DEPRECATIONS_CHANNEL"</span>: <span class="hljs-string">"null"</span>,
   <span class="hljs-attr">"LOG_LEVEL"</span>: <span class="hljs-string">"debug"</span>,
   <span class="hljs-attr">"DB_CONNECTION"</span>: <span class="hljs-string">"mysql"</span>,
   <span class="hljs-attr">"DB_HOST"</span>: <span class="hljs-string">"localhost"</span>,
   <span class="hljs-attr">"DB_PORT"</span>: <span class="hljs-string">"3306"</span>,
   <span class="hljs-attr">"DB_DATABASE"</span>: <span class="hljs-string">"laravel"</span>,
   <span class="hljs-attr">"DB_USERNAME"</span>: <span class="hljs-string">"root"</span>,
   <span class="hljs-attr">"DB_PASSWORD"</span>: <span class="hljs-string">""</span>,
   <span class="hljs-attr">"SESSION_DRIVER"</span>: <span class="hljs-string">"database"</span>,
   <span class="hljs-attr">"SESSION_LIFETIME"</span>: <span class="hljs-string">"120"</span>,
   <span class="hljs-attr">"SESSION_ENCRYPT"</span>: <span class="hljs-string">"false"</span>,
   <span class="hljs-attr">"SESSION_PATH"</span>: <span class="hljs-string">"/"</span>,
   <span class="hljs-attr">"SESSION_DOMAIN"</span>: <span class="hljs-string">"null"</span>,
   <span class="hljs-attr">"BROADCAST_CONNECTION"</span>: <span class="hljs-string">"log"</span>,
   <span class="hljs-attr">"FILESYSTEM_DISK"</span>: <span class="hljs-string">"local"</span>,
   <span class="hljs-attr">"QUEUE_CONNECTION"</span>: <span class="hljs-string">"database"</span>,
   <span class="hljs-attr">"CACHE_STORE"</span>: <span class="hljs-string">"database"</span>,
   <span class="hljs-attr">"CACHE_PREFIX"</span>: <span class="hljs-string">""</span>,
   <span class="hljs-attr">"MEMCACHED_HOST"</span>: <span class="hljs-string">"127.0.0.1"</span>,
   <span class="hljs-attr">"REDIS_CLIENT"</span>: <span class="hljs-string">"phpredis"</span>,
   <span class="hljs-attr">"REDIS_HOST"</span>: <span class="hljs-string">"127.0.0.1"</span>,
   <span class="hljs-attr">"REDIS_PASSWORD"</span>: <span class="hljs-string">"null"</span>,
   <span class="hljs-attr">"REDIS_PORT"</span>: <span class="hljs-string">"6379"</span>,
   <span class="hljs-attr">"MAIL_MAILER"</span>: <span class="hljs-string">"log"</span>,
   <span class="hljs-attr">"MAIL_HOST"</span>: <span class="hljs-string">"127.0.0.1"</span>,
   <span class="hljs-attr">"MAIL_PORT"</span>: <span class="hljs-string">"2525"</span>,
   <span class="hljs-attr">"MAIL_USERNAME"</span>: <span class="hljs-string">"null"</span>,
   <span class="hljs-attr">"MAIL_PASSWORD"</span>: <span class="hljs-string">"null"</span>,
   <span class="hljs-attr">"MAIL_ENCRYPTION"</span>: <span class="hljs-string">"null"</span>,
   <span class="hljs-attr">"MAIL_FROM_ADDRESS"</span>: <span class="hljs-string">"hello@example.com"</span>,
   <span class="hljs-attr">"MAIL_FROM_NAME"</span>: <span class="hljs-string">"Laravel"</span>,
   <span class="hljs-attr">"AWS_ACCESS_KEY_ID"</span>: <span class="hljs-string">""</span>,
   <span class="hljs-attr">"AWS_SECRET_ACCESS_KEY"</span>: <span class="hljs-string">""</span>,
   <span class="hljs-attr">"AWS_DEFAULT_REGION"</span>: <span class="hljs-string">"us-east-1"</span>,
   <span class="hljs-attr">"AWS_BUCKET"</span>: <span class="hljs-string">""</span>,
   <span class="hljs-attr">"AWS_USE_PATH_STYLE_ENDPOINT"</span>: <span class="hljs-string">"false"</span>,
   <span class="hljs-attr">"VITE_APP_NAME"</span>: <span class="hljs-string">"Laravel"</span>
 }
</code></pre>
</li>
<li><p>Click "Next"</p>
</li>
<li><p>Name your secret (e.g., "YourApp-ENV")</p>
</li>
<li><p>Add a description (optional)</p>
</li>
<li><p>Click "Next"</p>
</li>
<li><p>Leave rotation settings at defaults and click "Next"</p>
</li>
<li><p>Review and click "Store"</p>
</li>
<li><p>Note the ARN of your secret: <code>arn:aws:secretsmanager:region:account-id:secret:YourApp-ENV-xxxxxx</code></p>
</li>
</ol>
<h3 id="heading-creating-an-ecr-repository">Creating an ECR Repository</h3>
<p>Now, let's create an ECR repository to store our Docker images:</p>
<ol>
<li><p>Navigate to the Amazon ECR console</p>
</li>
<li><p>Click "Create repository"</p>
</li>
<li><p>Enter a name for your repository (e.g., "your-app-name")</p>
</li>
<li><p>Configure settings as needed (typically defaults are fine)</p>
</li>
<li><p>Click "Create repository"</p>
</li>
<li><p>Note the repository URI: <code>account-id.dkr.ecr.region.amazonaws.com/your-app-name</code></p>
</li>
</ol>
<h3 id="heading-setting-up-the-ecs-cluster">Setting Up the ECS Cluster</h3>
<p>Next, let's create our ECS cluster:</p>
<ol>
<li><p>Navigate to the Amazon ECS console</p>
</li>
<li><p>Click "Create Cluster"</p>
</li>
<li><p>Select "Networking only" (we'll use Fargate)</p>
</li>
<li><p>Click "Next step"</p>
</li>
<li><p>Enter a cluster name (e.g., "your-app-cluster")</p>
</li>
<li><p>Leave other options at defaults</p>
</li>
<li><p>Click "Create"</p>
</li>
</ol>
<h3 id="heading-creating-a-target-group-and-load-balancer">Creating a Target Group and Load Balancer</h3>
<p>Now, let's set up a load balancer to distribute traffic to our application:</p>
<ol>
<li><p>Navigate to the EC2 console, then to "Target Groups"</p>
</li>
<li><p>Click "Create target group"</p>
</li>
<li><p>Choose "IP addresses" as target type (for Fargate)</p>
</li>
<li><p>Enter a name for your target group (e.g., "your-app-tg")</p>
</li>
<li><p>Set protocol to HTTP and port to 80</p>
</li>
<li><p>Select your VPC</p>
</li>
<li><p>Set health check path to <code>/up</code> (this matches our healthcheck in the task definition)</p>
</li>
<li><p>Configure advanced settings if needed</p>
</li>
<li><p>Click "Create"</p>
</li>
<li><p>Note the ARN of your target group</p>
</li>
</ol>
<p>Next, create the Application Load Balancer:</p>
<ol>
<li><p>Navigate to the EC2 console, then to "Load Balancers"</p>
</li>
<li><p>Click "Create Load Balancer"</p>
</li>
<li><p>Select "Application Load Balancer"</p>
</li>
<li><p>Enter a name for your load balancer (e.g., "your-app-alb")</p>
</li>
<li><p>Select "internet-facing"</p>
</li>
<li><p>Select your VPC and at least two subnets from different availability zones</p>
</li>
<li><p>Create or select a security group that allows HTTP/HTTPS traffic</p>
</li>
<li><p>Configure listeners:</p>
<ul>
<li><p>Add a listener on port 80</p>
</li>
<li><p>Optionally add a listener on port 443 with SSL/TLS certificate</p>
</li>
</ul>
</li>
<li><p>Configure routing to the target group you created earlier</p>
</li>
<li><p>Review and create the load balancer</p>
</li>
<li><p>Note the DNS name of your load balancer</p>
</li>
</ol>
<h3 id="heading-creating-the-ecstaskexecutionrole">Creating the ecsTaskExecutionRole</h3>
<p>Before your ECS tasks can run properly, you need to create the ecsTaskExecutionRole that was referenced in the task definition:</p>
<ol>
<li><p>Navigate to the IAM console in your AWS account</p>
</li>
<li><p>Click on "Roles" and then "Create role"</p>
</li>
<li><p>Select "AWS service" as the trusted entity type</p>
</li>
<li><p>Choose "Elastic Container Service" from the service list</p>
</li>
<li><p>Select "Elastic Container Service Task" as the use case</p>
</li>
<li><p>Click "Next: Permissions"</p>
</li>
<li><p>Search for and select the following policies:</p>
<ul>
<li><p>AmazonECSTaskExecutionRolePolicy (this gives the role permission to pull images and send logs)</p>
</li>
<li><p>SecretsManagerReadWrite (if your tasks need to access Secrets Manager)</p>
</li>
</ul>
</li>
<li><p>Click "Next: Tags" (add tags if needed)</p>
</li>
<li><p>Click "Next: Review"</p>
</li>
<li><p>Enter "ecsTaskExecutionRole" as the role name</p>
</li>
<li><p>Add a description such as "Allows ECS tasks to call AWS services on your behalf"</p>
</li>
<li><p>Click "Create role"</p>
</li>
</ol>
<p>This role allows ECS to:</p>
<ul>
<li><p>Pull container images from ECR</p>
</li>
<li><p>Send container logs to CloudWatch Logs</p>
</li>
<li><p>Access secrets from AWS Secrets Manager (if needed by your application)</p>
</li>
</ul>
<p>Make sure to note the ARN of this role as you'll need it for your task definition:</p>
<pre><code class="lang-plaintext">arn:aws:iam::your-account-id:role/ecsTaskExecutionRole
</code></pre>
<p>You'll need to update your task-definition.json file with this ARN in the "executionRoleArn" field.</p>
<h3 id="heading-creating-the-ecs-service">Creating the ECS Service</h3>
<p>Before running your GitHub Actions workflow, you need to create an ECS service:</p>
<ol>
<li><p>Navigate to the ECS console, select your cluster</p>
</li>
<li><p>Click "Create service"</p>
</li>
<li><p>Select "FARGATE" as the launch type</p>
</li>
<li><p>Enter a service name (e.g., "your-app-service")</p>
</li>
<li><p>Set Number of tasks to 1 (or more for high availability)</p>
</li>
<li><p>Leave other options at defaults</p>
</li>
<li><p>Click "Next step"</p>
</li>
<li><p>Configure networking:</p>
<ul>
<li><p>Select your VPC</p>
</li>
<li><p>Select at least two subnets in different availability zones</p>
</li>
<li><p>Select a security group that allows inbound traffic on port 80 from the load balancer</p>
</li>
</ul>
</li>
<li><p>Click "Next step"</p>
</li>
<li><p>Configure load balancing:</p>
<ul>
<li><p>Select "Application Load Balancer"</p>
</li>
<li><p>Select your load balancer</p>
</li>
<li><p>Add your container to the load balancer with port 80</p>
</li>
<li><p>Select your target group</p>
</li>
</ul>
</li>
<li><p>Configure health check grace period if needed</p>
</li>
<li><p>Click "Next step"</p>
</li>
<li><p>Configure auto scaling if needed (optional)</p>
</li>
<li><p>Click "Next step"</p>
</li>
<li><p>Review and click "Create service"</p>
</li>
</ol>
<h2 id="heading-preparing-your-laravel-application">Preparing Your Laravel Application</h2>
<h3 id="heading-dockerfile-setup">Dockerfile Setup</h3>
<p>Create a <code>Dockerfile</code> in the root of your Laravel project:</p>
<pre><code class="lang-dockerfile"><span class="hljs-keyword">ARG</span> COMPOSER_VERSION=<span class="hljs-number">2.7</span>
<span class="hljs-keyword">ARG</span> PHP_VERSION=<span class="hljs-number">8.2</span>
<span class="hljs-keyword">ARG</span> NODE_VERSION=<span class="hljs-number">20</span>
<span class="hljs-comment">###########################################</span>
<span class="hljs-comment"># Prepare vendor images</span>
<span class="hljs-comment">###########################################</span>
<span class="hljs-keyword">FROM</span> composer:${COMPOSER_VERSION} AS vendor

<span class="hljs-comment"># Node.js installation</span>
<span class="hljs-keyword">FROM</span> node:${NODE_VERSION}-alpine AS node

<span class="hljs-comment">###########################################</span>
<span class="hljs-comment"># Build Backend and running web server</span>
<span class="hljs-comment">###########################################</span>
<span class="hljs-comment"># Use PHP 8.2 FPM Alpine as the base image</span>
<span class="hljs-keyword">FROM</span> php:${PHP_VERSION}-fpm-alpine AS server

<span class="hljs-keyword">ARG</span> PROJECT_DIR=/var/www/html
<span class="hljs-keyword">ENV</span> TZ=Australia/Sydney
<span class="hljs-comment"># Set the working directory inside the container</span>
<span class="hljs-keyword">WORKDIR</span><span class="bash"> <span class="hljs-variable">$PROJECT_DIR</span></span>

<span class="hljs-comment"># Install system dependencies and PHP extensions</span>
<span class="hljs-keyword">RUN</span><span class="bash"> apk add --no-cache nginx libpng libzip icu supervisor bash \
    &amp;&amp; apk add --no-cache --virtual .build-deps \
    <span class="hljs-variable">$PHPIZE_DEPS</span> \
    libpng-dev \
    libzip-dev \
    icu-dev \
    &amp;&amp; docker-php-ext-install opcache pdo pdo_mysql zip gd intl pcntl \
    &amp;&amp; docker-php-ext-configure opcache --enable-opcache \
    &amp;&amp; apk del .build-deps \
    &amp;&amp; rm -rf /var/cache/apk/*</span>

<span class="hljs-comment"># Install and configure cron</span>
<span class="hljs-keyword">RUN</span><span class="bash"> apk add --no-cache dcron \
    &amp;&amp; mkdir -p /var/<span class="hljs-built_in">log</span>/cron \
    &amp;&amp; touch /var/<span class="hljs-built_in">log</span>/cron/cron.log</span>

<span class="hljs-keyword">RUN</span><span class="bash"> apk add --no-cache tzdata \
    &amp;&amp; cp /usr/share/zoneinfo/<span class="hljs-variable">$TZ</span> /etc/localtime \
    &amp;&amp; <span class="hljs-built_in">echo</span> <span class="hljs-variable">$TZ</span> &gt; /etc/timezone \
    &amp;&amp; apk del tzdata</span>

<span class="hljs-keyword">RUN</span><span class="bash"> apk add --no-cache curl</span>

<span class="hljs-comment"># Copy Composer from its image</span>
<span class="hljs-keyword">COPY</span><span class="bash"> --chown=www-data:www-data --from=vendor /usr/bin/composer /usr/bin/composer</span>
<span class="hljs-keyword">COPY</span><span class="bash"> --chown=www-data:www-data composer.json composer.lock ./</span>

<span class="hljs-comment"># copy .env file</span>
<span class="hljs-keyword">COPY</span><span class="bash"> --chown=www-data:www-data .env .env</span>

<span class="hljs-keyword">RUN</span><span class="bash"> composer install --no-dev --optimize-autoloader --no-scripts</span>

<span class="hljs-comment"># Copy Node.js from its image</span>
<span class="hljs-keyword">COPY</span><span class="bash"> --from=node /usr/<span class="hljs-built_in">local</span> /usr/<span class="hljs-built_in">local</span></span>

<span class="hljs-comment"># Install NPM dependencies</span>
<span class="hljs-keyword">COPY</span><span class="bash"> --chown=www-data:www-data package.json package-lock.json ./</span>
<span class="hljs-keyword">RUN</span><span class="bash"> npm cache clean --force \
    &amp;&amp; npm install -g yarn --force \
    &amp;&amp; yarn</span>


<span class="hljs-comment"># Copy application files</span>
<span class="hljs-keyword">COPY</span><span class="bash"> --chown=www-data:www-data . <span class="hljs-variable">$PROJECT_DIR</span></span>

<span class="hljs-keyword">RUN</span><span class="bash"> yarn build</span>

<span class="hljs-keyword">RUN</span><span class="bash"> mkdir -p storage/framework/sessions \
    storage/framework/views \
    storage/framework/cache \
    storage/framework/testing \
    storage/logs \
    bootstrap/cache \
    &amp;&amp; chmod -R 775 storage bootstrap/cache</span>

<span class="hljs-comment"># Copy Nginx configuration file</span>
<span class="hljs-keyword">COPY</span><span class="bash"> docker/nginx.conf /etc/nginx/nginx.conf</span>

<span class="hljs-comment"># Copy custom php.ini file to override PHP settings</span>
<span class="hljs-keyword">COPY</span><span class="bash"> docker/php.ini /usr/<span class="hljs-built_in">local</span>/etc/php/conf.d/php-custom.ini</span>

<span class="hljs-comment"># Copy entrypoint script</span>
<span class="hljs-keyword">COPY</span><span class="bash"> docker/entrypoint.sh /usr/<span class="hljs-built_in">local</span>/bin/entrypoint.sh</span>
<span class="hljs-keyword">RUN</span><span class="bash"> chmod +x /usr/<span class="hljs-built_in">local</span>/bin/entrypoint.sh</span>

<span class="hljs-comment"># Set entrypoint script to start both PHP-FPM and Nginx</span>
<span class="hljs-keyword">ENTRYPOINT</span><span class="bash"> [<span class="hljs-string">"sh"</span>, <span class="hljs-string">"/usr/local/bin/entrypoint.sh"</span>]</span>

<span class="hljs-comment"># Expose port 80</span>
<span class="hljs-keyword">EXPOSE</span> <span class="hljs-number">80</span>
</code></pre>
<h3 id="heading-nginx-configuration">Nginx Configuration</h3>
<p>Create a directory named <code>docker</code> in your project root and add an <code>nginx.conf</code> file:</p>
<pre><code class="lang-nginx"><span class="hljs-attribute">user</span> nginx;  <span class="hljs-comment"># Use 'nginx' user or the default user for the image if running unprivileged</span>
<span class="hljs-attribute">worker_processes</span> auto;

<span class="hljs-attribute">error_log</span> /var/log/nginx/error.log <span class="hljs-literal">warn</span>;
<span class="hljs-attribute">pid</span> /var/run/nginx.pid;

<span class="hljs-section">events</span> {
    <span class="hljs-attribute">worker_connections</span> <span class="hljs-number">1024</span>;
}

<span class="hljs-attribute">daemon</span> <span class="hljs-literal">off</span>;

<span class="hljs-section">http</span> {
    <span class="hljs-attribute">include</span> /etc/nginx/mime.types;
    <span class="hljs-attribute">default_type</span> application/octet-stream;

    <span class="hljs-attribute">log_format</span> main <span class="hljs-string">'<span class="hljs-variable">$remote_addr</span> - <span class="hljs-variable">$remote_user</span> [<span class="hljs-variable">$time_local</span>] "<span class="hljs-variable">$request</span>" '</span>
                      <span class="hljs-string">'<span class="hljs-variable">$status</span> <span class="hljs-variable">$body_bytes_sent</span> "<span class="hljs-variable">$http_referer</span>" '</span>
                      <span class="hljs-string">'"<span class="hljs-variable">$http_user_agent</span>" "<span class="hljs-variable">$http_x_forwarded_for</span>"'</span>;

    <span class="hljs-attribute">access_log</span> /var/log/nginx/access.log main;

    <span class="hljs-attribute">sendfile</span> <span class="hljs-literal">on</span>;
    <span class="hljs-attribute">keepalive_timeout</span> <span class="hljs-number">65</span>;
    <span class="hljs-attribute">gzip</span> <span class="hljs-literal">on</span>;
    <span class="hljs-attribute">gzip_disable</span> <span class="hljs-string">"msie6"</span>;

    <span class="hljs-section">server</span> {
        <span class="hljs-attribute">listen</span> <span class="hljs-number">80</span>;  <span class="hljs-comment"># Cloud Run default port</span>

        <span class="hljs-attribute">server_name</span> _;  <span class="hljs-comment"># Accepts all hostnames</span>

        <span class="hljs-attribute">root</span> /var/www/html/public;  <span class="hljs-comment"># Laravel's public directory</span>

        <span class="hljs-attribute">index</span> index.php index.html index.htm;

        <span class="hljs-attribute">location</span> / {
            <span class="hljs-attribute">try_files</span> <span class="hljs-variable">$uri</span> <span class="hljs-variable">$uri</span>/ /index.php<span class="hljs-variable">$is_args</span><span class="hljs-variable">$args</span>;
        }

        <span class="hljs-attribute">location</span> <span class="hljs-regexp">~ \.php$</span> {
            <span class="hljs-attribute">include</span> fastcgi_params;
            <span class="hljs-attribute">fastcgi_pass</span> <span class="hljs-number">127.0.0.1:9000</span>;  <span class="hljs-comment"># Assuming PHP-FPM is running locally in the container</span>
            <span class="hljs-attribute">fastcgi_index</span> index.php;
            <span class="hljs-attribute">fastcgi_param</span> SCRIPT_FILENAME <span class="hljs-variable">$document_root</span><span class="hljs-variable">$fastcgi_script_name</span>;
            <span class="hljs-attribute">fastcgi_param</span> PATH_INFO <span class="hljs-variable">$fastcgi_path_info</span>;
            <span class="hljs-attribute">fastcgi_split_path_info</span><span class="hljs-regexp"> ^(.+?\.php)(/.+)$</span>;
            <span class="hljs-comment"># fastcgi_param HTTPS on;  # This is often needed for Laravel in production</span>
        }

        <span class="hljs-attribute">location</span> <span class="hljs-regexp">~ /\.ht</span> {
            <span class="hljs-attribute">deny</span> all;
        }

        <span class="hljs-comment"># Static file caching rules (optional, tweak for your needs)</span>
        <span class="hljs-attribute">location</span> <span class="hljs-regexp">~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2|ttf|svg|eot)$</span> {
            <span class="hljs-attribute">expires</span> <span class="hljs-number">30d</span>;
            <span class="hljs-attribute">add_header</span> Cache-Control <span class="hljs-string">"public, no-transform"</span>;
        }
    }
}
</code></pre>
<h3 id="heading-php-configuration">PHP Configuration</h3>
<p>Add a <code>php.ini</code> file in the <code>docker</code> directory:</p>
<pre><code class="lang-ini"><span class="hljs-comment">; php.ini</span>
<span class="hljs-attr">memory_limit</span> = <span class="hljs-number">512</span>M
<span class="hljs-attr">upload_max_filesize</span> = <span class="hljs-number">10</span>M
</code></pre>
<h3 id="heading-entrypoint-script">Entrypoint Script</h3>
<p>Add an <code>entrypoint.sh</code> script in the <code>docker</code> directory:</p>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/sh</span>
<span class="hljs-comment">#set -e</span>

<span class="hljs-comment"># Function to run migrations with error handling</span>
<span class="hljs-function"><span class="hljs-title">run_migrations</span></span>() {
    <span class="hljs-built_in">echo</span> <span class="hljs-string">"Running migrations"</span>
    <span class="hljs-keyword">if</span> php artisan migrate; <span class="hljs-keyword">then</span>
        <span class="hljs-built_in">echo</span> <span class="hljs-string">"Migrations completed successfully"</span>
    <span class="hljs-keyword">else</span>
        <span class="hljs-built_in">echo</span> <span class="hljs-string">"Migration failed, attempting to cache resources anyway"</span>
    <span class="hljs-keyword">fi</span>
}

<span class="hljs-comment"># Run migrations</span>
run_migrations

<span class="hljs-built_in">exec</span> <span class="hljs-string">"<span class="hljs-variable">$@</span>"</span>

<span class="hljs-comment"># Start PHP-FPM in the background</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Starting PHP-FPM..."</span>
php-fpm --nodaemonize &amp;
PHP_FPM_PID=$!

<span class="hljs-comment"># Start Nginx in the background</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Starting Nginx..."</span>
nginx &amp;
NGINX_PID=$!

<span class="hljs-comment"># Wait for all background processes</span>
<span class="hljs-built_in">wait</span> <span class="hljs-variable">$NGINX_PID</span> <span class="hljs-variable">$PHP_FPM_PID</span>
</code></pre>
<h2 id="heading-creating-the-ecs-task-definition">Creating the ECS Task Definition</h2>
<p>Create a <code>task-definition.json</code> file in your project root:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"family"</span>: <span class="hljs-string">"your-app-name"</span>,
    <span class="hljs-attr">"networkMode"</span>: <span class="hljs-string">"awsvpc"</span>,
    <span class="hljs-attr">"containerDefinitions"</span>: [
        {
            <span class="hljs-attr">"name"</span>: <span class="hljs-string">"your-app-container"</span>,
            <span class="hljs-attr">"image"</span>: <span class="hljs-string">"your-account-id.dkr.ecr.your-region.amazonaws.com/your-app-name:latest"</span>,
            <span class="hljs-attr">"essential"</span>: <span class="hljs-literal">true</span>,
            <span class="hljs-attr">"portMappings"</span>: [
                {
                    <span class="hljs-attr">"containerPort"</span>: <span class="hljs-number">80</span>,
                    <span class="hljs-attr">"hostPort"</span>: <span class="hljs-number">80</span>
                }
            ],
            <span class="hljs-attr">"logConfiguration"</span>: {
                <span class="hljs-attr">"logDriver"</span>: <span class="hljs-string">"awslogs"</span>,
                <span class="hljs-attr">"options"</span>: {
                    <span class="hljs-attr">"awslogs-group"</span>: <span class="hljs-string">"your-app-logs"</span>,
                    <span class="hljs-attr">"awslogs-region"</span>: <span class="hljs-string">"your-region"</span>,
                    <span class="hljs-attr">"awslogs-stream-prefix"</span>: <span class="hljs-string">"ecs"</span>
                }
            },
            <span class="hljs-attr">"healthCheck"</span>: {
                <span class="hljs-attr">"command"</span>: [
                    <span class="hljs-string">"CMD-SHELL"</span>,
                    <span class="hljs-string">"curl -f http://localhost:80/up || exit 1"</span>
                ],
                <span class="hljs-attr">"interval"</span>: <span class="hljs-number">30</span>,
                <span class="hljs-attr">"timeout"</span>: <span class="hljs-number">5</span>,
                <span class="hljs-attr">"retries"</span>: <span class="hljs-number">3</span>,
                <span class="hljs-attr">"startPeriod"</span>: <span class="hljs-number">60</span>
            }
        }
    ],
    <span class="hljs-attr">"requiresCompatibilities"</span>: [<span class="hljs-string">"FARGATE"</span>],
    <span class="hljs-attr">"cpu"</span>: <span class="hljs-string">"256"</span>,
    <span class="hljs-attr">"memory"</span>: <span class="hljs-string">"512"</span>,
    <span class="hljs-attr">"executionRoleArn"</span>: <span class="hljs-string">"arn:aws:iam::your-account-id:role/ecsTaskExecutionRole"</span>
}
</code></pre>
<p>Be sure to create a <code>/up</code> endpoint in your Laravel application that returns a 200 status code for health checks. This can be as simple as:</p>
<pre><code class="lang-php"><span class="hljs-comment">// In routes/web.php</span>
Route::get(<span class="hljs-string">'/up'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> response(<span class="hljs-string">'OK'</span>, <span class="hljs-number">200</span>);
});
</code></pre>
<h2 id="heading-setting-up-github-actions-workflow">Setting Up GitHub Actions Workflow</h2>
<p>Create a <code>.github/workflows</code> directory in your project root and add an <code>ecs-deploy.yaml</code> file:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">Laravel</span> <span class="hljs-string">to</span> <span class="hljs-string">AWS</span> <span class="hljs-string">ECS</span>

<span class="hljs-attr">on:</span>
  <span class="hljs-attr">push:</span>
    <span class="hljs-attr">branches:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">main</span>  <span class="hljs-comment"># or your production branch</span>

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">deploy:</span>
    <span class="hljs-attr">name:</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">to</span> <span class="hljs-string">AWS</span> <span class="hljs-string">ECS</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>

    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Checkout</span> <span class="hljs-string">Code</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v4</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Set</span> <span class="hljs-string">up</span> <span class="hljs-string">AWS</span> <span class="hljs-string">CLI</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">aws-actions/configure-aws-credentials@v2</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">aws-access-key-id:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.AWS_ACCESS_KEY_ID</span> <span class="hljs-string">}}</span>
          <span class="hljs-attr">aws-secret-access-key:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.AWS_SECRET_ACCESS_KEY</span> <span class="hljs-string">}}</span>
          <span class="hljs-attr">aws-region:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.AWS_REGION</span> <span class="hljs-string">}}</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Check</span> <span class="hljs-string">AWS</span> <span class="hljs-string">CLI</span> <span class="hljs-string">Configuration</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">aws</span> <span class="hljs-string">sts</span> <span class="hljs-string">get-caller-identity</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Flush</span> <span class="hljs-string">DNS</span> <span class="hljs-string">Cache</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">sudo</span> <span class="hljs-string">systemctl</span> <span class="hljs-string">restart</span> <span class="hljs-string">systemd-resolved</span> <span class="hljs-string">||</span> <span class="hljs-string">sudo</span> <span class="hljs-string">systemd-resolve</span> <span class="hljs-string">--flush-caches</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Update</span> <span class="hljs-string">Docker</span> <span class="hljs-string">DNS</span> <span class="hljs-string">settings</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">|
            echo '{"dns":["8.8.8.8","8.8.4.4"]}' | sudo tee /etc/docker/daemon.json
            sudo systemctl restart docker
</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Retrieve</span> <span class="hljs-string">Secrets</span> <span class="hljs-string">from</span> <span class="hljs-string">AWS</span> <span class="hljs-string">Secrets</span> <span class="hljs-string">Manager</span>
        <span class="hljs-attr">id:</span> <span class="hljs-string">secrets</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">|
          # Get secrets in JSON format
          SECRET_JSON=$(aws secretsmanager get-secret-value --secret-id ${{ secrets.AWS_SECRET_ARN }} --query SecretString --output text)
</span>
          <span class="hljs-comment"># Convert JSON to KEY=VALUE format for .env file</span>
          <span class="hljs-string">echo</span> <span class="hljs-string">"$SECRET_JSON"</span> <span class="hljs-string">|</span> <span class="hljs-string">jq</span> <span class="hljs-string">-r</span> <span class="hljs-string">'to_entries|map("\(.key)=\(.value|tostring)")|.[]'</span> <span class="hljs-string">&gt;</span> <span class="hljs-string">.env</span>

          <span class="hljs-comment"># Verify the .env file (don't print sensitive info in logs)</span>
          <span class="hljs-string">echo</span> <span class="hljs-string">"Created .env file with the following keys:"</span>
          <span class="hljs-string">grep</span> <span class="hljs-string">-v</span> <span class="hljs-string">"PASSWORD\|KEY"</span> <span class="hljs-string">.env</span> <span class="hljs-string">|</span> <span class="hljs-string">cut</span> <span class="hljs-string">-d=</span> <span class="hljs-string">-f1</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Login</span> <span class="hljs-string">to</span> <span class="hljs-string">Amazon</span> <span class="hljs-string">ECR</span>
        <span class="hljs-attr">id:</span> <span class="hljs-string">login-ecr</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">|
          aws ecr get-login-password --region ${{ secrets.AWS_REGION }} | docker login --username AWS --password-stdin ${{ secrets.ECR_REPOSITORY }}
</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Build</span> <span class="hljs-string">Docker</span> <span class="hljs-string">Image</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">|
          docker build -t ${{ secrets.ECR_REPOSITORY }}:latest .
</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Push</span> <span class="hljs-string">Docker</span> <span class="hljs-string">Image</span> <span class="hljs-string">to</span> <span class="hljs-string">ECR</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">|
          docker push ${{ secrets.ECR_REPOSITORY }}:latest
</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Update</span> <span class="hljs-string">ECS</span> <span class="hljs-string">Task</span> <span class="hljs-string">Definition</span>
        <span class="hljs-attr">id:</span> <span class="hljs-string">task-def</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">|
            # Use the task-definition.json file from the project root
            # Update the image in the task definition file
            jq '.containerDefinitions[0].image = "${{ secrets.ECR_REPOSITORY }}:latest"' task-definition.json &gt; updated-task-definition.json
</span>
            <span class="hljs-comment"># Register the new task definition</span>
            <span class="hljs-string">NEW_REVISION=$(aws</span> <span class="hljs-string">ecs</span> <span class="hljs-string">register-task-definition</span> <span class="hljs-string">--cli-input-json</span> <span class="hljs-string">file://updated-task-definition.json)</span>
            <span class="hljs-string">TASK_REVISION=$(echo</span> <span class="hljs-string">$NEW_REVISION</span> <span class="hljs-string">|</span> <span class="hljs-string">jq</span> <span class="hljs-string">-r</span> <span class="hljs-string">'.taskDefinition.taskDefinitionArn'</span><span class="hljs-string">)</span>
            <span class="hljs-string">echo</span> <span class="hljs-string">"TASK_REVISION=$TASK_REVISION"</span> <span class="hljs-string">&gt;&gt;</span> <span class="hljs-string">$GITHUB_ENV</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">New</span> <span class="hljs-string">Task</span> <span class="hljs-string">Definition</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">|
            aws ecs update-service \
              --cluster ${{ secrets.ECS_CLUSTER }} \
              --service ${{ secrets.ECS_SERVICE }} \
              --task-definition $TASK_REVISION \
              --load-balancers "[{\"targetGroupArn\": \"${{ secrets.TARGET_GROUP_ARN }}\", \"containerName\": \"${{ secrets.CONTAINER_NAME }}\", \"containerPort\": 80}]"</span>
</code></pre>
<p>Add the following secrets to your GitHub repository:</p>
<ol>
<li><p><code>AWS_ACCESS_KEY_ID</code>: Your IAM user access key</p>
</li>
<li><p><code>AWS_SECRET_ACCESS_KEY</code>: Your IAM user secret key</p>
</li>
<li><p><code>AWS_REGION</code>: Your AWS region (e.g., ap-southeast-2)</p>
</li>
<li><p><code>ECR_REPOSITORY</code>: Your ECR repository URI</p>
</li>
<li><p><code>ECS_CLUSTER</code>: Your ECS cluster name</p>
</li>
<li><p><code>ECS_SERVICE</code>: Your ECS service name</p>
</li>
<li><p><code>AWS_SECRET_ARN</code>: The ARN of your secret in AWS Secrets Manager</p>
</li>
<li><p><code>TARGET_GROUP_ARN</code>: The ARN of your target group</p>
</li>
<li><p><code>CONTAINER_NAME</code>: The name of your container (should match the name in task-definition.json)</p>
</li>
</ol>
<h2 id="heading-testing-the-cicd-pipeline">Testing the CI/CD Pipeline</h2>
<p>Now it's time to test your CI/CD pipeline:</p>
<ol>
<li><p>Make a change to your Laravel application</p>
</li>
<li><p>Commit and push the changes to your main branch</p>
</li>
<li><p>Monitor the GitHub Actions workflow in the "Actions" tab of your repository</p>
</li>
<li><p>Once the workflow completes successfully, check your ECS service in the AWS console</p>
</li>
<li><p>Visit your load balancer's DNS name to see your application in action</p>
</li>
</ol>
<h2 id="heading-monitoring-and-troubleshooting">Monitoring and Troubleshooting</h2>
<p>To monitor your application and troubleshoot issues:</p>
<ol>
<li><p><strong>CloudWatch Logs</strong>: Check the logs from your ECS task</p>
<ul>
<li><p>Navigate to CloudWatch in the AWS console</p>
</li>
<li><p>Go to "Log groups" and find your application's log group</p>
</li>
</ul>
</li>
<li><p><strong>ECS Task Status</strong>: Check the status of your ECS tasks</p>
<ul>
<li><p>Navigate to ECS in the AWS console</p>
</li>
<li><p>Select your cluster and service</p>
</li>
<li><p>Check the "Tasks" tab to see running tasks and their status</p>
</li>
</ul>
</li>
<li><p><strong>Load Balancer Health</strong>: Check the health of your target group</p>
<ul>
<li><p>Navigate to EC2 in the AWS console</p>
</li>
<li><p>Go to "Target Groups" and select your target group</p>
</li>
<li><p>Check the "Targets" tab to see the health status of your instances</p>
</li>
</ul>
</li>
<li><p><strong>GitHub Actions Workflow</strong>: Check the workflow logs for any issues</p>
<ul>
<li><p>Navigate to the "Actions" tab in your GitHub repository</p>
</li>
<li><p>Select the latest workflow run</p>
</li>
<li><p>Check the logs for each step</p>
</li>
</ul>
</li>
</ol>
<h2 id="heading-best-practices">Best Practices</h2>
<ol>
<li><p><strong>Environment Variables</strong>: Keep sensitive information in AWS Secrets Manager</p>
</li>
<li><p><strong>Versioning</strong>: Use Git tags or commit hashes for image versioning in production</p>
</li>
<li><p><strong>Scaling</strong>: Configure auto-scaling for your ECS service based on CPU and memory usage</p>
</li>
<li><p><strong>Monitoring</strong>: Set up CloudWatch alarms for important metrics</p>
</li>
<li><p><strong>Security</strong>: Use IAM roles with least privilege principles</p>
</li>
<li><p><strong>Backup</strong>: Regularly backup your database and critical data</p>
</li>
<li><p><strong>Testing</strong>: Implement automated testing in your CI/CD pipeline</p>
</li>
<li><p><strong>Rollback Plan</strong>: Have a plan for rolling back deployments if issues occur</p>
</li>
</ol>
<h2 id="heading-conclusion">Conclusion</h2>
<p>You have now set up a complete CI/CD pipeline for your Laravel application using AWS ECS, ECR, and GitHub Actions. This pipeline automates the build, test, and deployment process, allowing you to deliver updates to your application with confidence.</p>
<p>By leveraging containerization with Docker and the scalability of AWS ECS, you've created a robust infrastructure that can handle your application's growth. The integration with AWS Secrets Manager ensures that your sensitive information is kept secure, while the Application Load Balancer provides high availability and distributes traffic efficiently.</p>
<p>Remember to regularly review and update your pipeline as your application evolves, and consider implementing additional features such as blue/green deployments or canary releases for even more reliability.</p>
<p>Happy coding!</p>
]]></content:encoded></item><item><title><![CDATA[Understanding AWS CloudWatch]]></title><description><![CDATA[Understanding Amazon CloudWatch: Your Home's Smart Monitoring System in the Cloud
Imagine you just moved into a smart home. You have sensors that tell you when doors are opened, how much electricity you're using, and if the temperature is too high. T...]]></description><link>https://notes.sohag.pro/understanding-aws-cloudwatch</link><guid isPermaLink="true">https://notes.sohag.pro/understanding-aws-cloudwatch</guid><category><![CDATA[AWS]]></category><category><![CDATA[#CloudWatch]]></category><dc:creator><![CDATA[Sohag Hasan]]></dc:creator><pubDate>Thu, 13 Feb 2025 16:58:47 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1739465840405/0ed2941c-ced5-407c-be83-93821929c67b.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-understanding-amazon-cloudwatch-your-homes-smart-monitoring-system-in-the-cloud">Understanding Amazon CloudWatch: Your Home's Smart Monitoring System in the Cloud</h1>
<p>Imagine you just moved into a smart home. You have sensors that tell you when doors are opened, how much electricity you're using, and if the temperature is too high. That's exactly what Amazon CloudWatch does for your applications in AWS – it's your all-in-one monitoring system for your cloud resources.</p>
<h2 id="heading-what-is-cloudwatch">What is CloudWatch?</h2>
<p>CloudWatch is like having a super-attentive building manager for your cloud applications. Just as your smart home system alerts you when something's wrong, CloudWatch keeps an eye on your AWS resources and applications, collecting data and sending alerts when needed.</p>
<h2 id="heading-real-world-examples">Real-World Examples</h2>
<h3 id="heading-monitoring-like-a-smart-fridge">Monitoring Like a Smart Fridge</h3>
<p>Think about a modern refrigerator that tracks temperature and sends alerts to your phone if it gets too warm. CloudWatch does the same for your servers – if a server starts running too hot (high CPU usage) or is running out of space, it'll notify you before your ice cream melts (or before your application crashes).</p>
<h3 id="heading-utility-bills-tracking">Utility Bills Tracking</h3>
<p>Just like you monitor your monthly water and electricity usage, CloudWatch tracks your AWS resource consumption. It helps you understand patterns – like knowing you use more electricity during dinner time, CloudWatch shows you when your application gets the most traffic.</p>
<h2 id="heading-key-features">Key Features</h2>
<h3 id="heading-metrics">Metrics</h3>
<p>Like checking your smart watch for steps, heart rate, and sleep quality, CloudWatch collects various metrics from your applications:</p>
<ul>
<li><p>CPU usage (how hard your server is working)</p>
</li>
<li><p>Memory usage (how much information it's juggling)</p>
</li>
<li><p>Network traffic (how many visitors you're getting)</p>
</li>
</ul>
<h3 id="heading-alarms">Alarms</h3>
<p>Similar to setting a burglar alarm at home, you can set CloudWatch alarms to alert you when something needs attention. For example, if your website starts responding slowly, you'll get notified immediately.</p>
<h3 id="heading-logs">Logs</h3>
<p>Just as your smart doorbell keeps a video history of visitors, CloudWatch keeps detailed logs of everything happening in your applications.</p>
<h2 id="heading-pro-tip-getting-laravel-logs-from-ecs-to-cloudwatch">Pro Tip: Getting Laravel Logs from ECS to CloudWatch</h2>
<p>Here's a handy trick for Laravel developers using Amazon ECS. To send your Laravel application logs to CloudWatch, you just need to make a simple configuration change. Here's how:</p>
<ol>
<li>First, in your Laravel <code>.env</code> file, set:</li>
</ol>
<pre><code class="lang-yaml"><span class="hljs-string">LOG_CHANNEL=stderr</span>
</code></pre>
<ol start="2">
<li>In your ECS task definition, ensure logging is configured:</li>
</ol>
<pre><code class="lang-json">{
    <span class="hljs-attr">"logConfiguration"</span>: {
        <span class="hljs-attr">"logDriver"</span>: <span class="hljs-string">"awslogs"</span>,
        <span class="hljs-attr">"options"</span>: {
            <span class="hljs-attr">"awslogs-group"</span>: <span class="hljs-string">"/ecs/your-app-name"</span>,
            <span class="hljs-attr">"awslogs-region"</span>: <span class="hljs-string">"your-region"</span>,
            <span class="hljs-attr">"awslogs-stream-prefix"</span>: <span class="hljs-string">"ecs"</span>
        }
    }
}
</code></pre>
<p>This setup makes Laravel write logs to stderr, which ECS automatically forwards to CloudWatch. It's like setting up your smart home devices to all report to one central app – everything's in one place!</p>
<h2 id="heading-getting-started">Getting Started</h2>
<p>Starting with CloudWatch is like setting up your first smart home device:</p>
<ol>
<li><p>Log into your AWS Console</p>
</li>
<li><p>Navigate to CloudWatch</p>
</li>
<li><p>Start with basic metrics that AWS collects automatically</p>
</li>
<li><p>Gradually add more specific monitoring as you learn what's important for your application</p>
</li>
</ol>
<h2 id="heading-best-practices">Best Practices</h2>
<ol>
<li><p>Don't monitor everything at once. Start with the basics, like CPU and memory usage.</p>
</li>
<li><p>Set up meaningful alerts – like getting a notification when your website's error rate exceeds normal levels.</p>
</li>
<li><p>Keep your logs organized by using logical naming conventions.</p>
</li>
</ol>
<p>CloudWatch might seem overwhelming at first, but think of it as your application's fitness tracker – it's there to help you keep everything healthy and running smoothly. Start small, learn from the data you collect, and gradually expand your monitoring as your needs grow.</p>
<p>Remember, just as you wouldn't want to run a smart home without any monitoring, you shouldn't run cloud applications without CloudWatch keeping an eye on things. It's your 24/7 digital superintendent, making sure everything runs smoothly while you focus on building great applications.</p>
]]></content:encoded></item><item><title><![CDATA[Understanding Amazon Virtual Private Cloud (VPC): Your Network's Private Sanctuary]]></title><description><![CDATA[Amazon Virtual Private Cloud (VPC)
What is a VPC?
Imagine a VPC as your personal, secure digital neighborhood in the cloud. Just like a gated community has specific boundaries and rules, a VPC provides a logically isolated section of the AWS cloud wh...]]></description><link>https://notes.sohag.pro/amazon-virtual-private-cloud-vpc</link><guid isPermaLink="true">https://notes.sohag.pro/amazon-virtual-private-cloud-vpc</guid><category><![CDATA[AWS]]></category><category><![CDATA[vpc]]></category><dc:creator><![CDATA[Sohag Hasan]]></dc:creator><pubDate>Fri, 07 Feb 2025 18:38:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1738953283497/42f49440-a43e-42bb-a439-b147aa8f15dc.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-amazon-virtual-private-cloud-vpc">Amazon Virtual Private Cloud (VPC)</h1>
<h2 id="heading-what-is-a-vpc">What is a VPC?</h2>
<p>Imagine a VPC as your personal, secure digital neighborhood in the cloud. Just like a gated community has specific boundaries and rules, a VPC provides a logically isolated section of the AWS cloud where you can launch resources with complete control over network configuration.</p>
<h2 id="heading-key-vpc-fundamentals">Key VPC Fundamentals</h2>
<h3 id="heading-1-vpc-structure">1. VPC Structure</h3>
<ul>
<li><p>A VPC exists within a specific AWS region</p>
</li>
<li><p>Can contain multiple Availability Zones (AZs)</p>
</li>
<li><p>Requires two primary components:</p>
<ol>
<li><p>Region selection</p>
</li>
<li><p>IP address range (e.g., 10.1.0.0/16)</p>
</li>
</ol>
</li>
</ul>
<h3 id="heading-2-subnets-the-organized-neighborhoods">2. Subnets: The Organized Neighborhoods</h3>
<p>Think of subnets like different neighborhoods within your digital community. Each subnet:</p>
<ul>
<li><p>Belongs to a specific VPC</p>
</li>
<li><p>Exists in a single Availability Zone</p>
</li>
<li><p>Has a unique IP range (subset of VPC's CIDR range)</p>
</li>
<li><p>Example: 10.1.1.0/24 within a 10.1.0.0/16 VPC</p>
</li>
</ul>
<h2 id="heading-network-access-and-connectivity">Network Access and Connectivity</h2>
<h3 id="heading-internet-gateway">Internet Gateway</h3>
<p>The internet gateway is like a controlled entrance/exit to your digital neighborhood. It:</p>
<ul>
<li><p>Provides internet access to your VPC</p>
</li>
<li><p>Must be explicitly connected to be functional</p>
</li>
<li><p>Acts as a bridge between your private network and the public internet</p>
</li>
</ul>
<h3 id="heading-virtual-private-gateway-vpg">Virtual Private Gateway (VPG)</h3>
<p>Consider this your secure, encrypted tunnel connecting your AWS network to another private network. It's like a private, guarded bridge between two exclusive communities.</p>
<h2 id="heading-reserved-ip-addresses-the-infrastructure-buffer">Reserved IP Addresses: The Infrastructure Buffer</h2>
<p>AWS reserves five IP addresses in each subnet for critical infrastructure:</p>
<ul>
<li><p>Used for routing</p>
</li>
<li><p>DNS configuration</p>
</li>
<li><p>Network management</p>
</li>
<li><p>Reduces usable IP addresses in a subnet</p>
</li>
</ul>
<h3 id="heading-real-world-example">Real-World Example</h3>
<p>In a 10.0.0.0/22 VPC with 1,024 total IPs:</p>
<ul>
<li><p>Divided into four /24 subnets</p>
</li>
<li><p>Each subnet has 256 IP addresses</p>
</li>
<li><p>Only 251 IPs are actually available for use</p>
</li>
</ul>
<h2 id="heading-advanced-connectivity-options">Advanced Connectivity Options</h2>
<h3 id="heading-aws-direct-connect">AWS Direct Connect</h3>
<p>Think of this as a dedicated, private fiber-optic cable directly connecting your on-premises data center to AWS. Benefits include:</p>
<ul>
<li><p>Secure physical connection</p>
</li>
<li><p>Reduced network costs</p>
</li>
<li><p>Consistent network performance</p>
</li>
<li><p>Direct access to AWS services</p>
</li>
</ul>
<h2 id="heading-routing-and-security">Routing and Security</h2>
<h3 id="heading-route-tables">Route Tables</h3>
<ul>
<li><p>Main route table: Default network traffic configuration</p>
</li>
<li><p>Custom route tables: Granular control over network traffic</p>
</li>
<li><p>Can define specific routing rules for different subnets</p>
</li>
</ul>
<h3 id="heading-network-access-control-lists-nacls">Network Access Control Lists (NACLs)</h3>
<p>Imagine NACLs as subnet-level firewalls. Key characteristics:</p>
<ul>
<li><p>Stateless security mechanism</p>
</li>
<li><p>Control inbound and outbound traffic</p>
</li>
<li><p>Can allow or deny specific protocols, ports, and IP ranges</p>
</li>
</ul>
<h2 id="heading-best-practices">Best Practices</h2>
<ol>
<li><p>Use a /16 VPC range for flexibility</p>
</li>
<li><p>Create /24 subnets for manageable IP allocation</p>
</li>
<li><p>Implement custom route tables for granular control</p>
</li>
<li><p>Use NACLs for additional security layers</p>
</li>
<li><p>Carefully plan IP ranges and subnet divisions</p>
</li>
</ol>
<h2 id="heading-conclusion">Conclusion</h2>
<p>A VPC is more than just a network—it's a sophisticated, secure, and flexible environment for hosting your cloud infrastructure. By understanding its components and leveraging its features, you can create robust, scalable, and secure cloud architectures.</p>
]]></content:encoded></item><item><title><![CDATA[Navigating the Digital Highway: Understanding IP Addresses and CIDR Blocks from Scratch]]></title><description><![CDATA[Understanding IP Addresses and CIDR Blocks from Scratch
What is an IP Address? Your Digital Home Address
Imagine the internet as a massive city, and each device is like a house. Just as every house has a unique address, every device connected to the ...]]></description><link>https://notes.sohag.pro/ip-cidr-blocks</link><guid isPermaLink="true">https://notes.sohag.pro/ip-cidr-blocks</guid><category><![CDATA[ip address]]></category><category><![CDATA[CIDR]]></category><dc:creator><![CDATA[Sohag Hasan]]></dc:creator><pubDate>Fri, 07 Feb 2025 18:25:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1738952511283/eb4e79a2-4caf-48d1-a74a-de02d283bcb1.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-understanding-ip-addresses-and-cidr-blocks-from-scratch">Understanding IP Addresses and CIDR Blocks from Scratch</h1>
<h2 id="heading-what-is-an-ip-address-your-digital-home-address">What is an IP Address? Your Digital Home Address</h2>
<p>Imagine the internet as a massive city, and each device is like a house. Just as every house has a unique address, every device connected to the internet has a unique identifier called an IP (Internet Protocol) address. This address helps data find its way from one device to another, just like a postal address helps mail reach the right destination.</p>
<h2 id="heading-binary-and-decimal-the-language-of-computers">Binary and Decimal: The Language of Computers</h2>
<h3 id="heading-understanding-binary">Understanding Binary</h3>
<p>Binary is the computer's native language - a system using only two digits: 0 and 1. Think of it like a light switch that can only be on (1) or off (0). Every piece of digital information is essentially a series of these switches.</p>
<h3 id="heading-decimal-our-familiar-number-system">Decimal: Our Familiar Number System</h3>
<p>Decimal is the number system we use daily, with 10 digits (0-9). When we talk about IP addresses, we typically use decimal notation.</p>
<h3 id="heading-conversion-magic-binary-to-decimal">Conversion Magic: Binary to Decimal</h3>
<h4 id="heading-easy-conversion-trick">Easy Conversion Trick</h4>
<p>Each binary digit (bit) represents a power of 2:</p>
<ul>
<li><p>Far right bit = 2^0 (1)</p>
</li>
<li><p>Next bit = 2^1 (2)</p>
</li>
<li><p>Next bit = 2^2 (4)</p>
</li>
<li><p>And so on...</p>
</li>
</ul>
<p><strong>Example Conversion:</strong> Binary: 1010</p>
<ul>
<li><p>1 × 2³ = 8</p>
</li>
<li><p>0 × 2² = 0</p>
</li>
<li><p>1 × 2¹ = 2</p>
</li>
<li><p>0 × 2⁰ = 0 Result: 8 + 0 + 2 + 0 = 10 (Decimal)</p>
</li>
</ul>
<h2 id="heading-ip-address-structure">IP Address Structure</h2>
<p>An IP address is typically 32 bits long (IPv4), divided into four octets:</p>
<ul>
<li><p>Each octet is 8 bits</p>
</li>
<li><p>Range: 0-255 in decimal</p>
</li>
<li><p>Example: 192.168.1.1</p>
</li>
</ul>
<h3 id="heading-ip-address-classes">IP Address Classes</h3>
<ul>
<li><p>Class A: 1.0.0.0 to 126.255.255.255</p>
</li>
<li><p>Class B: 128.0.0.0 to 191.255.255.255</p>
</li>
<li><p>Class C: 192.0.0.0 to 223.255.255.255</p>
</li>
</ul>
<h2 id="heading-cidr-classless-inter-domain-routing">CIDR: Classless Inter-Domain Routing</h2>
<p>CIDR is like a flexible zoning system for internet addresses. Instead of rigid address classes, it allows more precise network segmentation.</p>
<h3 id="heading-cidr-notation">CIDR Notation</h3>
<p>Format: IP Address/Prefix Length</p>
<ul>
<li><p>Example: 192.168.1.0/24</p>
</li>
<li><p>"/24" means first 24 bits are network portion</p>
</li>
<li><p>Meaning 24/8=3, first 3 portion is fixed, only last portion can be changed to 0-255</p>
</li>
<li><p><img src="https://blog.kakaocdn.net/dn/lixUW/btsES3cOq4G/4dxGeO0KwwxBCKRhvJgBnK/img.png" alt /></p>
</li>
</ul>
<h3 id="heading-real-world-analogy">Real-World Analogy</h3>
<p>Think of CIDR like a neighborhood:</p>
<ul>
<li><p>IP Address = Specific house</p>
</li>
<li><p>Prefix = Defining the entire neighborhood boundaries</p>
</li>
</ul>
<h3 id="heading-subnet-mask-conversion">Subnet Mask Conversion</h3>
<ul>
<li><p>/24 = 255.255.255.0</p>
</li>
<li><p>/16 = 255.255.0.0</p>
</li>
<li><p>/8 = 255.0.0.0</p>
</li>
</ul>
<h2 id="heading-practical-applications">Practical Applications</h2>
<h3 id="heading-network-segmentation">Network Segmentation</h3>
<ul>
<li><p>Businesses use CIDR to:</p>
<ul>
<li><p>Organize network infrastructure</p>
</li>
<li><p>Implement security boundaries</p>
</li>
<li><p>Manage IP address allocation efficiently</p>
</li>
</ul>
</li>
</ul>
<h3 id="heading-cloud-and-hosting">Cloud and Hosting</h3>
<ul>
<li><p>Cloud providers use CIDR blocks to:</p>
<ul>
<li><p>Allocate IP ranges to customers</p>
</li>
<li><p>Manage network isolation</p>
</li>
<li><p>Enable secure multi-tenant environments</p>
</li>
</ul>
</li>
</ul>
<h2 id="heading-advanced-considerations">Advanced Considerations</h2>
<h3 id="heading-ipv6">IPv6</h3>
<ul>
<li><p>128-bit address space</p>
</li>
<li><p>Solves IP address exhaustion</p>
</li>
<li><p>Notation: 2001:0db8:85a3:0000:0000:8a2e:0370:7334</p>
</li>
</ul>
<h3 id="heading-subnetting-strategies">Subnetting Strategies</h3>
<ul>
<li><p>Calculate usable host addresses</p>
</li>
<li><p>Plan network growth</p>
</li>
<li><p>Optimize network performance</p>
</li>
</ul>
<h2 id="heading-common-challenges-and-solutions">Common Challenges and Solutions</h2>
<h3 id="heading-ip-address-exhaustion">IP Address Exhaustion</h3>
<ul>
<li><p>NAT (Network Address Translation)</p>
</li>
<li><p>IPv6 adoption</p>
</li>
<li><p>Dynamic IP allocation</p>
</li>
</ul>
<h3 id="heading-security-implications">Security Implications</h3>
<ul>
<li><p>Use of private IP ranges</p>
</li>
<li><p>Implementing firewall rules</p>
</li>
<li><p>Network segmentation</p>
</li>
</ul>
<h2 id="heading-pro-tips">Pro Tips</h2>
<ul>
<li><p>Always have a network addressing plan</p>
</li>
<li><p>Use online CIDR calculators</p>
</li>
<li><p>Understand your network's specific requirements</p>
</li>
<li><p>Regularly audit and optimize IP allocations</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Understanding IP addresses and CIDR blocks is like mastering the road map of the digital world. With practice, you'll navigate network configurations with confidence!</p>
]]></content:encoded></item><item><title><![CDATA[From Chaos to Control: How Terraform Turns Your Cloud Infrastructure into a Well-Oiled Machine!]]></title><description><![CDATA[How Terraform Turns Your Cloud Infrastructure into a Well-Oiled Machine!
Imagine you're planning a big party, and instead of manually setting up each decoration, arranging chairs, and preparing food, you have a magical assistant who does everything e...]]></description><link>https://notes.sohag.pro/terraform-cloud-infrastructure</link><guid isPermaLink="true">https://notes.sohag.pro/terraform-cloud-infrastructure</guid><category><![CDATA[Terraform]]></category><category><![CDATA[Cloud infrastructure]]></category><category><![CDATA[#IaC]]></category><dc:creator><![CDATA[Sohag Hasan]]></dc:creator><pubDate>Fri, 07 Feb 2025 18:02:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1738951207335/2153843f-12ab-42a9-8c75-e0454a3390e0.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-how-terraform-turns-your-cloud-infrastructure-into-a-well-oiled-machine">How Terraform Turns Your Cloud Infrastructure into a Well-Oiled Machine!</h1>
<p>Imagine you're planning a big party, and instead of manually setting up each decoration, arranging chairs, and preparing food, you have a magical assistant who does everything exactly how you want with just one command. That's essentially what Terraform does for your digital infrastructure!</p>
<h2 id="heading-what-is-terraform">What is Terraform?</h2>
<p>Terraform is like a universal remote control for your cloud resources. It's an Infrastructure as Code (IaC) tool that lets you describe and provision all your technology infrastructure using simple, human-readable configuration files. Instead of clicking through complex web consoles or running multiple manual commands, you write a script that defines exactly what you want - and Terraform makes it happen.</p>
<h2 id="heading-real-life-example-building-your-digital-lego-set">Real-Life Example: Building Your Digital Lego Set</h2>
<p>Think of Terraform like a sophisticated Lego set for tech professionals. Just as you'd follow a blueprint to build a complex Lego structure, Terraform lets you create entire computer environments with a few lines of code.</p>
<p>In our specific example, we're using Terraform to effortlessly spin up an Nginx web server:</p>
<pre><code class="lang-yaml"><span class="hljs-string">resource</span> <span class="hljs-string">"docker_container"</span> <span class="hljs-string">"nginx"</span> {
  <span class="hljs-string">image</span> <span class="hljs-string">=</span> <span class="hljs-string">docker_image.nginx.image_id</span>
  <span class="hljs-string">name</span>  <span class="hljs-string">=</span> <span class="hljs-string">"tutorial"</span>

  <span class="hljs-string">ports</span> {
    <span class="hljs-string">internal</span> <span class="hljs-string">=</span> <span class="hljs-number">80</span>
    <span class="hljs-string">external</span> <span class="hljs-string">=</span> <span class="hljs-number">8000</span>
  }
}
</code></pre>
<p>This tiny snippet does something that would typically require multiple manual steps: it pulls an Nginx image, creates a container, and maps network ports.</p>
<h2 id="heading-why-should-you-care">Why Should You Care?</h2>
<h3 id="heading-1-consistency-is-king">1. Consistency is King</h3>
<p>Imagine telling 10 people to make a sandwich. You'll get 10 different sandwiches. Terraform ensures every "sandwich" (server, network, database) is identical, every single time.</p>
<h3 id="heading-2-version-control-for-infrastructure">2. Version Control for Infrastructure</h3>
<p>Just like Google Docs tracks changes, Terraform keeps a history of your infrastructure. Want to roll back to last week's setup? No problem!</p>
<h3 id="heading-3-automation-less-human-error">3. Automation = Less Human Error</h3>
<p>Humans make mistakes. Computers, when properly instructed, are precise. Terraform removes the "oops" factor from infrastructure management.</p>
<h3 id="heading-4-multi-cloud-flexibility">4. Multi-Cloud Flexibility</h3>
<p>Whether you're using AWS, Azure, or Google Cloud, Terraform speaks their language. One tool, endless possibilities.</p>
<h2 id="heading-getting-started-is-easier-than-you-think">Getting Started is Easier Than You Think</h2>
<p>Our example shows how simple it can be:</p>
<ol>
<li><p>Install Terraform</p>
</li>
<li><p>Write a short configuration file</p>
</li>
<li><p>Run <code>terraform apply</code></p>
</li>
<li><p>Boom! Your infrastructure is live</p>
</li>
</ol>
<h2 id="heading-where-to-start">Where to start?</h2>
<p>Just go there and choose your favourite cloud: <a target="_blank" href="https://developer.hashicorp.com/terraform/tutorials?product_intent=terraform">https://developer.hashicorp.com/terraform/tutorials?product_intent=terraform</a></p>
<h2 id="heading-the-bottom-line">The Bottom Line</h2>
<p>Terraform transforms complex, error-prone infrastructure management into a predictable, repeatable process. It's like having a super-smart assistant who never gets tired, never makes careless mistakes, and can rebuild your entire digital world with a single command.</p>
<p>Ready to level up your tech game? Terraform is your new best friend. 🚀🖥️</p>
]]></content:encoded></item><item><title><![CDATA[Prayers at a Glance: Your Mac's Ultimate Spiritual Companion 🕌✨]]></title><description><![CDATA[How to show prayer times in menu bar (MacOS)
Ever wished your Mac could keep you connected to your spiritual routine without constant phone-checking? I've got a super simple hack that'll transform your menu bar into a prayer time tracker!
What You'll...]]></description><link>https://notes.sohag.pro/prayers-at-a-glance-your-macs-ultimate-spiritual-companion</link><guid isPermaLink="true">https://notes.sohag.pro/prayers-at-a-glance-your-macs-ultimate-spiritual-companion</guid><category><![CDATA[calendar]]></category><category><![CDATA[macOS]]></category><dc:creator><![CDATA[Sohag Hasan]]></dc:creator><pubDate>Fri, 24 Jan 2025 06:03:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1737697003527/68e2c48f-1310-4aa8-bd20-32f27a29f2d9.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-how-to-show-prayer-times-in-menu-bar-macos">How to show prayer times in menu bar (MacOS)</h1>
<p>Ever wished your Mac could keep you connected to your spiritual routine without constant phone-checking? I've got a super simple hack that'll transform your menu bar into a prayer time tracker!</p>
<h2 id="heading-what-youll-need">What You'll Need:</h2>
<ul>
<li><p>A Mac</p>
</li>
<li><p>Internet connection</p>
</li>
<li><p>Google Calendar</p>
</li>
<li><p>Notion Calendar</p>
</li>
</ul>
<h2 id="heading-step-by-step-prayer-time-setup">Step-by-Step Prayer Time Setup:</h2>
<ol>
<li><p><strong>Find Your Prayer Web Calendar</strong></p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737698325111/1f8feb33-a83f-443b-b1d8-c53de9add229.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>Visit <a target="_blank" href="https://prayerwebcal.dsultan.com">https://prayerwebcal.dsultan.com</a></p>
</li>
<li><p>Set up your specific location</p>
</li>
<li><p>Customize prayer time settings</p>
</li>
</ul>
</li>
<li><p><strong>Grab Your ICS URL</strong></p>
<ul>
<li><p>Scroll to the bottom of the page</p>
</li>
<li><p>Copy the unique URL, something like this:<br />  <a target="_blank" href="https://prayerwebcal.dsultan.com/ics/Dhaka_Dhaka_Bangladesh/cs=1:do=15:es=1:id=1:j=1:js=1:mv=1.0:nm=12:tz=Asia%2FDhaka:x=23.804:y=90.415"><code>https://prayerwebcal.dsultan.com/ics/Dhaka_Dhaka_Bangladesh/cs=1:do=15:es=1:id=1:j=1:js=1:mv=1.0:nm=12:tz=Asia%2FDhaka:x=23.804:y=90.415</code></a></p>
</li>
</ul>
</li>
<li><p><strong>Add to Google Calendar</strong></p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737698149256/195887d8-88be-4472-8eb8-69db35c21ea0.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>Open Google Calendar</p>
</li>
<li><p>Click the "+" icon next to "Other Calendars"</p>
</li>
<li><p>Select "From URL”</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737698253149/cd259281-e94b-4331-a4d5-8e9e8ae7e7a0.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Paste your copied prayer time URL</p>
</li>
<li><p>Click "Add Calendar"</p>
</li>
</ul>
</li>
<li><p><strong>Install Notion Calendar</strong></p>
<ul>
<li><p>Download from <a target="_blank" href="https://www.notion.com/product/calendar">https://www.notion.com/product/calendar</a></p>
</li>
<li><p>Install and log in with your Google account</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737698452407/8d1b8b9e-4512-40c8-92b9-2b7affa6f11f.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>From Settings &gt; General &gt; Set to run on startup</p>
</li>
</ul>
</li>
<li><p><strong>Configure Menu Bar</strong></p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737698555961/ab831029-519f-4db9-b7f9-f8d74f4131c2.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>Open Notion Calendar settings</p>
</li>
<li><p>Click on "Menu Bar"</p>
</li>
<li><p>Enable Menu Bar</p>
</li>
<li><p>Adjust display preferences</p>
</li>
</ul>
</li>
</ol>
<p>And voilà! Your Mac's menu bar is now your personal prayer time companion. No more missed prayers or constant phone-checking – spiritual mindfulness, meet tech convenience! 🙌📱</p>
]]></content:encoded></item><item><title><![CDATA[The Junior Dev's Guide to Deploying Laravel on cPanel (Without the Public Folder Hassle!)]]></title><description><![CDATA[Deploying Laravel on cPanel
Hey there, fellow developers! 👋 Remember your first Laravel deployment? Mine was a roller coaster of emotions that involved a lot of coffee, some hair-pulling moments, and finally, that sweet victory when everything worke...]]></description><link>https://notes.sohag.pro/deploying-laravel-on-cpanel</link><guid isPermaLink="true">https://notes.sohag.pro/deploying-laravel-on-cpanel</guid><category><![CDATA[Laravel]]></category><category><![CDATA[cpanel]]></category><category><![CDATA[hosting]]></category><dc:creator><![CDATA[Sohag Hasan]]></dc:creator><pubDate>Thu, 09 Jan 2025 05:08:31 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1736399076146/01e1cea9-d2bc-422b-8ead-5eddb5506bc8.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-deploying-laravel-on-cpanel">Deploying Laravel on cPanel</h1>
<p>Hey there, fellow developers! 👋 Remember your first Laravel deployment? Mine was a roller coaster of emotions that involved a lot of coffee, some hair-pulling moments, and finally, that sweet victory when everything worked. Today, I'm going to share how to deploy your Laravel application on cPanel without dealing with that pesky public folder configuration.</p>
<h2 id="heading-the-challenge">The Challenge</h2>
<p>Picture this: It's 9 PM, and you've just finished your first Laravel project for a client. You're feeling pretty good about yourself until you realize – oh wait, the client has a shared hosting with cPanel, and you need to deploy it TODAY. The traditional Laravel structure wants you to point to the public folder, but your client's hosting doesn't support that. Don't panic! I've got you covered.</p>
<h2 id="heading-the-solution">The Solution</h2>
<p>We're going to use a clever workaround that keeps your application secure while working within cPanel's limitations. Here's how:</p>
<h3 id="heading-step-1-prepare-your-project">Step 1: Prepare Your Project</h3>
<p>First, let's get your project ready for deployment:</p>
<ol>
<li><p>Run <code>composer install --optimize-autoloader --no-dev</code> in your local environment</p>
</li>
<li><p>Run <code>php artisan key:generate</code></p>
</li>
<li><p>Create a zip file of your entire Laravel project</p>
</li>
<li><p>Make sure your <code>.env</code> file is configured for production</p>
</li>
</ol>
<h3 id="heading-step-2-the-upload">Step 2: The Upload</h3>
<ol>
<li><p>Log into cPanel (take a deep breath, you got this!)</p>
</li>
<li><p>Navigate to File Manager</p>
</li>
<li><p>Go to <code>public_html</code></p>
</li>
<li><p>Upload your zip file and extract it here</p>
</li>
</ol>
<h3 id="heading-step-3-the-magic-files">Step 3: The Magic Files</h3>
<p>Now, here's where the magic happens. We need to create two special files in your root directory (public_html):</p>
<ol>
<li>First, create a <code>.htaccess</code> file with these contents:</li>
</ol>
<pre><code class="lang-apache"><span class="hljs-section">&lt;IfModule mod_rewrite.c&gt;</span>
    <span class="hljs-section">&lt;IfModule mod_negotiation.c&gt;</span>
        <span class="hljs-attribute"><span class="hljs-nomarkup">Options</span></span> -MultiViews -Indexes
    <span class="hljs-section">&lt;/IfModule&gt;</span>
    <span class="hljs-attribute"><span class="hljs-nomarkup">RewriteEngine</span></span> <span class="hljs-literal">On</span>
    <span class="hljs-attribute">php_value</span> open_basedir <span class="hljs-string">"/var/www/html:/tmp"</span>
    <span class="hljs-comment"># Handle Authorization Header</span>
    <span class="hljs-attribute"><span class="hljs-nomarkup">RewriteCond</span></span> <span class="hljs-variable">%{HTTP:Authorization}</span> .
    <span class="hljs-attribute"><span class="hljs-nomarkup">RewriteRule</span></span> .* -<span class="hljs-meta"> [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]</span>
    <span class="hljs-comment"># Redirect Trailing Slashes If Not A Folder...</span>
    <span class="hljs-attribute"><span class="hljs-nomarkup">RewriteCond</span></span> <span class="hljs-variable">%{REQUEST_FILENAME}</span> !-d
    <span class="hljs-attribute"><span class="hljs-nomarkup">RewriteCond</span></span> <span class="hljs-variable">%{REQUEST_URI}</span> (.+)/$
    <span class="hljs-attribute"><span class="hljs-nomarkup">RewriteRule</span></span> ^ %<span class="hljs-number">1</span><span class="hljs-meta"> [L,R=301]</span>
    <span class="hljs-comment"># Handle Front Controller...</span>
    <span class="hljs-attribute"><span class="hljs-nomarkup">RewriteCond</span></span> <span class="hljs-variable">%{REQUEST_FILENAME}</span> !-d
    <span class="hljs-attribute"><span class="hljs-nomarkup">RewriteCond</span></span> <span class="hljs-variable">%{REQUEST_FILENAME}</span> !-f
    <span class="hljs-attribute"><span class="hljs-nomarkup">RewriteRule</span></span> ^ index.php<span class="hljs-meta"> [L]</span>
<span class="hljs-section">&lt;/IfModule&gt;</span>
</code></pre>
<ol start="2">
<li>Create an <code>index.php</code> file:</li>
</ol>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>
$uri = urldecode(
    parse_url($_SERVER[<span class="hljs-string">'REQUEST_URI'</span>], PHP_URL_PATH)
);

<span class="hljs-keyword">if</span> ($uri !== <span class="hljs-string">'/'</span> &amp;&amp; file_exists(<span class="hljs-keyword">__DIR__</span>.<span class="hljs-string">'/public'</span>.$uri)) {
    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
}
<span class="hljs-keyword">require_once</span> <span class="hljs-keyword">__DIR__</span>.<span class="hljs-string">'/public/index.php'</span>;
</code></pre>
<h3 id="heading-step-4-the-asset-update-very-important">Step 4: The Asset Update (Very Important!)</h3>
<p>Here's a crucial step that many developers miss: You need to update all your asset URLs to include 'public/'. In your blade files, update your assets like this:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!-- Before --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/images/logo.png"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/css/app.css"</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/js/app.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

<span class="hljs-comment">&lt;!-- After --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/public/images/logo.png"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/public/css/app.css"</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/public/js/app.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<h2 id="heading-understanding-the-magic">Understanding the Magic</h2>
<p>Let's break down what these files do:</p>
<ul>
<li><p>The <code>.htaccess</code> file acts as your traffic controller. It tells Apache how to handle incoming requests and properly route them through your Laravel application. It's like a security guard who knows exactly where to send your visitors.</p>
</li>
<li><p>The <code>index.php</code> file is your bouncer. It catches all requests and forwards them to your actual Laravel application in the public folder. Think of it as a smart receptionist who knows how to handle every visitor.</p>
</li>
</ul>
<h2 id="heading-pro-tips-from-someone-who-learned-the-hard-way">Pro Tips from Someone Who Learned the Hard Way</h2>
<ol>
<li><p>Always keep a backup of your original files before making these changes</p>
</li>
<li><p>Test your asset paths thoroughly after deployment</p>
</li>
<li><p>Check your storage folder permissions (set to 755 for folders and 644 for files)</p>
</li>
<li><p>Don't forget to update your <code>.env</code> file with production settings</p>
</li>
</ol>
<h2 id="heading-troubleshooting-common-issues">Troubleshooting Common Issues</h2>
<ul>
<li><p>If your images aren't loading, double-check that you've added 'public/' to all asset URLs</p>
</li>
<li><p>Getting a 500 error? Check your storage folder permissions</p>
</li>
<li><p>Blank page? Enable error reporting in your <code>.env</code> file temporarily to see what's wrong</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>And there you have it! Your Laravel application is now running smoothly on cPanel without exposing your entire application structure. Remember, we all started somewhere, and these deployment challenges are just part of the journey to becoming a better developer.</p>
<p>Happy deploying! 🚀</p>
<p>P.S. Don't forget to celebrate with your favorite beverage when it all works – you've earned it!</p>
]]></content:encoded></item><item><title><![CDATA[🚀 Outsmarting GitHub Actions: A Cost-Effective Approval Workflow Without Breaking the Bank]]></title><description><![CDATA[A Cost-Effective Approval Workflow Without Breaking the Bank
In the world of continuous deployment, every second (and every penny) counts. Today, I'm going to show you a clever GitHub Actions hack that can save your team time and money while maintain...]]></description><link>https://notes.sohag.pro/outsmarting-github-actions-a-cost-effective-approval-workflow-without-breaking-the-bank</link><guid isPermaLink="true">https://notes.sohag.pro/outsmarting-github-actions-a-cost-effective-approval-workflow-without-breaking-the-bank</guid><category><![CDATA[manual approval]]></category><category><![CDATA[github-actions]]></category><dc:creator><![CDATA[Sohag Hasan]]></dc:creator><pubDate>Mon, 18 Nov 2024 15:47:26 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1731944762480/2e5966c1-48fd-4549-a3e4-97a38ccb266e.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-a-cost-effective-approval-workflow-without-breaking-the-bank">A Cost-Effective Approval Workflow Without Breaking the Bank</h1>
<p>In the world of continuous deployment, every second (and every penny) counts. Today, I'm going to show you a clever GitHub Actions hack that can save your team time and money while maintaining rock-solid deployment controls.</p>
<h2 id="heading-the-problem-with-traditional-approval-workflows">The Problem with Traditional Approval Workflows</h2>
<p>Manual workflow approvals in GitHub Actions are great in theory, but they come with a hidden cost. While the workflow waits for human approval, you're burning through your Actions minutes - essentially paying for waiting time. Not very efficient, right?</p>
<h2 id="heading-introducing-the-issue-based-approval-system">Introducing the Issue-Based Approval System</h2>
<p>What if we could create an approval workflow that:</p>
<ul>
<li><p><strong>Costs nothing while waiting</strong></p>
</li>
<li><p>Provides clear tracking</p>
</li>
<li><p><strong>Offers granular access control</strong></p>
</li>
<li><p>Works seamlessly with your existing GitHub workflow</p>
</li>
</ul>
<p>Let me introduce you to our ingenious solution: an Issue-Based Deployment Approval System.</p>
<h2 id="heading-how-it-works-the-science-behind-the-magic">✨ How It Works: The Science Behind the Magic</h2>
<h3 id="heading-workflow-trigger">Workflow Trigger</h3>
<ol>
<li><p>When code is pushed to the <code>dev</code> branch or a pull request is merged</p>
</li>
<li><p>An automatically created GitHub issue prompts for deployment approval</p>
</li>
</ol>
<h3 id="heading-approval-mechanism">Approval Mechanism</h3>
<ul>
<li><p>Only specific team members or team roles can approve</p>
</li>
<li><p>Approval is as simple as commenting "approve" or "LGTM" on the issue</p>
</li>
<li><p>Built-in security checks verify the approver's identity</p>
</li>
</ul>
<h3 id="heading-deployment">Deployment</h3>
<ul>
<li><p>Once approved, the deployment runs immediately</p>
</li>
<li><p>The approval issue is automatically closed</p>
</li>
<li><p>A comment tracks who approved and what was deployed</p>
</li>
</ul>
<h2 id="heading-a-real-world-example">A real world example</h2>
<p><a target="_blank" href="https://github.com/sohag-pro/action-approval/issues/8"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1731944151551/8528d959-35b5-429a-b251-3594517fc45a.png" alt="Action Approval Issue" class="image--center mx-auto" /></a></p>
<p>Wanna see if it’s true, check it here: <a target="_blank" href="https://github.com/sohag-pro/action-approval/issues/8">https://github.com/sohag-pro/action-approval/issues/8</a></p>
<p>Action Implemented Repo: <a target="_blank" href="https://github.com/sohag-pro/action-approval">https://github.com/sohag-pro/action-approval</a></p>
<p>Please give a ⭐ if you find it helpful.</p>
<p>I'll share the two key workflow files that make this magic happen:</p>
<h2 id="heading-1-issue-creation-workflow">1. Issue Creation Workflow</h2>
<p><code>.github/workflows/create-approval-issue.yml</code> file</p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">Create</span> <span class="hljs-string">Approval</span> <span class="hljs-string">Issue</span>

<span class="hljs-attr">on:</span>
  <span class="hljs-attr">push:</span>
    <span class="hljs-attr">branches:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">dev</span>
  <span class="hljs-attr">pull_request:</span>
    <span class="hljs-attr">types:</span> [<span class="hljs-string">closed</span>]
    <span class="hljs-attr">branches:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">dev</span>
<span class="hljs-attr">permissions:</span>
  <span class="hljs-attr">issues:</span> <span class="hljs-string">write</span>
  <span class="hljs-attr">contents:</span> <span class="hljs-string">read</span>

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">create-approval-issue:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-attr">if:</span> <span class="hljs-string">github.event.pull_request.merged</span> <span class="hljs-string">==</span> <span class="hljs-literal">true</span> <span class="hljs-string">||</span> <span class="hljs-string">github.event_name</span> <span class="hljs-string">==</span> <span class="hljs-string">'push'</span>
    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Create</span> <span class="hljs-string">Approval</span> <span class="hljs-string">Issue</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/github-script@v7</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">script:</span> <span class="hljs-string">|
            let commitSha = '';
            if (context.eventName === 'pull_request') {
              commitSha = context.payload.pull_request.merge_commit_sha;
            } else {
              commitSha = context.sha;
            }
</span>
            <span class="hljs-string">const</span> <span class="hljs-string">shortSha</span> <span class="hljs-string">=</span> <span class="hljs-string">commitSha.substring(0,</span> <span class="hljs-number">7</span><span class="hljs-string">);</span>

            <span class="hljs-string">const</span> <span class="hljs-string">issueBody</span> <span class="hljs-string">=</span> <span class="hljs-string">`</span>
            <span class="hljs-string">Please</span> <span class="hljs-string">review</span> <span class="hljs-string">and</span> <span class="hljs-string">approve</span> <span class="hljs-string">the</span> <span class="hljs-string">deployment</span> <span class="hljs-string">to</span> <span class="hljs-string">staging.</span>

            <span class="hljs-comment">### Approval Instructions</span>
            <span class="hljs-bullet">-</span> <span class="hljs-string">Only</span> <span class="hljs-string">authorized</span> <span class="hljs-string">team</span> <span class="hljs-string">members</span> <span class="hljs-string">can</span> <span class="hljs-string">approve</span> <span class="hljs-string">this</span> <span class="hljs-string">deployment</span>
            <span class="hljs-bullet">-</span> <span class="hljs-attr">Authorized approvers:</span>
              <span class="hljs-bullet">-</span> <span class="hljs-string">@sohag-pro</span>
              <span class="hljs-bullet">-</span> <span class="hljs-attr">Members of teams:</span> <span class="hljs-string">devops,</span> <span class="hljs-string">senior-developers</span>

            <span class="hljs-string">To</span> <span class="hljs-string">approve,</span> <span class="hljs-attr">comment with one of these keywords:</span> <span class="hljs-string">"approve"</span><span class="hljs-string">,</span> <span class="hljs-string">"LGTM"</span>

            <span class="hljs-string">---</span> 
            <span class="hljs-string">Metadata</span> <span class="hljs-string">(do</span> <span class="hljs-string">not</span> <span class="hljs-string">modify):</span>
            <span class="hljs-string">\`\`\`json</span>
            {
              <span class="hljs-attr">"commit_sha":</span> <span class="hljs-string">"${commitSha}"</span>,
              <span class="hljs-attr">"branch":</span> <span class="hljs-string">"dev"</span>,
              <span class="hljs-attr">"triggered_by":</span> <span class="hljs-string">"${context.eventName}"</span>
            }
            <span class="hljs-string">\`\`\`</span>
            <span class="hljs-string">`;</span>

            <span class="hljs-string">const</span> <span class="hljs-string">issue</span> <span class="hljs-string">=</span> <span class="hljs-string">await</span> <span class="hljs-string">github.rest.issues.create({</span>
              <span class="hljs-attr">owner:</span> <span class="hljs-string">context.repo.owner,</span>
              <span class="hljs-attr">repo:</span> <span class="hljs-string">context.repo.repo,</span>
              <span class="hljs-attr">title:</span> <span class="hljs-string">`Deploy</span> <span class="hljs-string">to</span> <span class="hljs-string">Staging</span> <span class="hljs-string">needs</span> <span class="hljs-string">approval</span> <span class="hljs-bullet">-</span> <span class="hljs-string">${shortSha}`,</span>
              <span class="hljs-attr">body:</span> <span class="hljs-string">issueBody,</span>
              <span class="hljs-attr">labels:</span> [<span class="hljs-string">'deployment-approval'</span>]
            <span class="hljs-string">});</span>
            <span class="hljs-string">console.log(`Created</span> <span class="hljs-string">issue</span> <span class="hljs-comment">#${issue.data.number}`);</span>
</code></pre>
<h2 id="heading-create-issue-workflow-explanation">🚀 <strong>Create Issue Workflow Explanation</strong></h2>
<h3 id="heading-trigger"><strong>Trigger</strong>:</h3>
<ol>
<li><p><code>push</code>: When a new commit is pushed to the <code>dev</code> branch.</p>
</li>
<li><p><code>pull_request</code>: When a pull request targeting the <code>dev</code> branch is merged.</p>
</li>
</ol>
<hr />
<h3 id="heading-permissions"><strong>Permissions</strong>:</h3>
<ul>
<li><p><code>issues: write</code>: To create an issue.</p>
</li>
<li><p><code>contents: read</code>: To read repository information.</p>
</li>
</ul>
<hr />
<h3 id="heading-job-create-approval-issue"><strong>Job</strong>: <code>create-approval-issue</code></h3>
<ul>
<li><strong>Runs-on</strong>: <code>ubuntu-latest</code>.</li>
</ul>
<h4 id="heading-condition"><strong>Condition</strong>:</h4>
<ul>
<li><p>The job runs if:</p>
<ul>
<li><p>A pull request was merged (<code>github.event.pull_request.merged == true</code>).</p>
</li>
<li><p>Or the event is a <code>push</code>.</p>
</li>
</ul>
</li>
</ul>
<hr />
<h4 id="heading-steps"><strong>Steps</strong>:</h4>
<ol>
<li><p><strong>Create Approval Issue</strong>:</p>
<ul>
<li><p>Uses the <code>actions/github-script</code> action.</p>
</li>
<li><p>Extracts the <strong>commit SHA</strong>:</p>
<ul>
<li><p>If the trigger is <code>pull_request</code>, it uses the <code>merge_commit_sha</code> of the pull request.</p>
</li>
<li><p>Otherwise, it uses the SHA of the latest pushed commit (<code>context.sha</code>).</p>
</li>
</ul>
</li>
<li><p>Creates a short SHA (first 7 characters) for readability.</p>
</li>
<li><p>Constructs an <strong>issue body</strong> that includes:</p>
<ul>
<li><p>Instructions for the approval process.</p>
</li>
<li><p>Metadata (commit SHA, branch, trigger source) in JSON format.</p>
</li>
</ul>
</li>
<li><p>Creates a new issue with:</p>
<ul>
<li><p><strong>Title</strong>: <code>Deploy to Staging needs approval - &lt;short SHA&gt;</code>.</p>
</li>
<li><p><strong>Body</strong>: Approval instructions and metadata.</p>
</li>
<li><p><strong>Label</strong>: <code>deployment-approval</code>.</p>
</li>
</ul>
</li>
</ul>
</li>
</ol>
<hr />
<h3 id="heading-purpose"><strong>Purpose</strong>:</h3>
<p>This workflow automates the creation of a tracking issue for deployment approval:</p>
<ul>
<li><p>Ensures all deployments to staging are documented and require explicit approval.</p>
</li>
<li><p>Simplifies the process for authorized users to approve a deployment by commenting on the issue.</p>
</li>
</ul>
<hr />
<h3 id="heading-key-highlights"><strong>Key Highlights</strong>:</h3>
<ul>
<li><p>Uses metadata for traceability (e.g., commit SHA, branch, and event source).</p>
</li>
<li><p>Directly ties deployments to commits or merge events for better tracking.</p>
</li>
<li><p>Encourages controlled deployments via a formal approval workflow.</p>
</li>
</ul>
<h2 id="heading-2-deployment-approval-workflow">2. Deployment Approval Workflow</h2>
<p><code>.github/workflows/deploy-staging.yml</code></p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">to</span> <span class="hljs-string">Staging</span>

<span class="hljs-attr">on:</span>
  <span class="hljs-attr">issue_comment:</span>
    <span class="hljs-attr">types:</span> [<span class="hljs-string">created</span>]
    <span class="hljs-attr">if:</span> <span class="hljs-string">|
      contains(github.event.issue.title, 'Deploy to Staging needs approval')
</span>
<span class="hljs-attr">permissions:</span>
  <span class="hljs-attr">issues:</span> <span class="hljs-string">write</span>
  <span class="hljs-attr">contents:</span> <span class="hljs-string">read</span>
  <span class="hljs-attr">pull-requests:</span> <span class="hljs-string">read</span>

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">process-approval:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>

    <span class="hljs-attr">if:</span> <span class="hljs-string">|
      contains(github.event.issue.title, 'Deploy to Staging needs approval') &amp;&amp;
      (contains(github.event.comment.body, 'approve') || contains(github.event.comment.body, 'LGTM'))
</span>    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Check</span> <span class="hljs-string">Approver</span>
        <span class="hljs-attr">id:</span> <span class="hljs-string">check-approver</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/github-script@v7</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">script:</span> <span class="hljs-string">|
            // Define allowed approvers
            const ALLOWED_APPROVERS = [
              'sohag-pro',
              'tech-lead',
              'devops-engineer'
            ];
</span>
            <span class="hljs-string">//</span> <span class="hljs-string">Define</span> <span class="hljs-string">allowed</span> <span class="hljs-string">teams</span> <span class="hljs-string">(team</span> <span class="hljs-string">slugs)</span>
            <span class="hljs-string">const</span> <span class="hljs-string">ALLOWED_TEAMS</span> <span class="hljs-string">=</span> [
              <span class="hljs-string">'devops'</span>,
              <span class="hljs-string">'senior-developers'</span>
            ]<span class="hljs-string">;</span>

            <span class="hljs-string">const</span> <span class="hljs-string">commenter</span> <span class="hljs-string">=</span> <span class="hljs-string">context.payload.comment.user.login;</span>
            <span class="hljs-string">console.log(`Comment</span> <span class="hljs-attr">by:</span> <span class="hljs-string">${commenter}`);</span>

            <span class="hljs-string">//</span> <span class="hljs-string">First</span> <span class="hljs-string">check</span> <span class="hljs-string">if</span> <span class="hljs-string">user</span> <span class="hljs-string">is</span> <span class="hljs-string">directly</span> <span class="hljs-string">in</span> <span class="hljs-string">allowed</span> <span class="hljs-string">list</span>
            <span class="hljs-string">if</span> <span class="hljs-string">(ALLOWED_APPROVERS.includes(commenter))</span> {
              <span class="hljs-string">console.log('Approver</span> <span class="hljs-string">is</span> <span class="hljs-string">in</span> <span class="hljs-string">allowed</span> <span class="hljs-string">users</span> <span class="hljs-string">list');</span>
              <span class="hljs-string">core.setOutput('status'</span>, <span class="hljs-string">'authorized'</span><span class="hljs-string">);</span>
              <span class="hljs-string">return;</span>
            }

            <span class="hljs-string">//</span> <span class="hljs-string">Check</span> <span class="hljs-string">if</span> <span class="hljs-string">user</span> <span class="hljs-string">is</span> <span class="hljs-string">member</span> <span class="hljs-string">of</span> <span class="hljs-string">allowed</span> <span class="hljs-string">teams</span>
            <span class="hljs-string">let</span> <span class="hljs-string">isTeamMember</span> <span class="hljs-string">=</span> <span class="hljs-literal">false</span><span class="hljs-string">;</span>
            <span class="hljs-string">for</span> <span class="hljs-string">(const</span> <span class="hljs-string">team</span> <span class="hljs-string">of</span> <span class="hljs-string">ALLOWED_TEAMS)</span> {
              <span class="hljs-string">try</span> {
                <span class="hljs-string">const</span> { <span class="hljs-attr">data:</span> <span class="hljs-string">isMember</span> } <span class="hljs-string">=</span> <span class="hljs-string">await</span> <span class="hljs-string">github.rest.teams.getMembershipForUserInOrg(</span>{
                  <span class="hljs-attr">org:</span> <span class="hljs-string">context.repo.owner</span>,
                  <span class="hljs-attr">team_slug:</span> <span class="hljs-string">team</span>,
                  <span class="hljs-attr">username:</span> <span class="hljs-string">commenter</span>
                }<span class="hljs-string">);</span>

                <span class="hljs-string">if</span> <span class="hljs-string">(isMember.state</span> <span class="hljs-string">===</span> <span class="hljs-string">'active'</span><span class="hljs-string">)</span> {
                  <span class="hljs-string">console.log(`Approver</span> <span class="hljs-attr">is member of team:</span> <span class="hljs-string">$</span>{<span class="hljs-string">team</span>}<span class="hljs-string">`);</span>
                  <span class="hljs-string">isTeamMember</span> <span class="hljs-string">=</span> <span class="hljs-literal">true</span><span class="hljs-string">;</span>
                  <span class="hljs-string">break;</span>
                }
              } <span class="hljs-string">catch</span> <span class="hljs-string">(error)</span> {
                <span class="hljs-string">console.log(`Error</span> <span class="hljs-string">checking</span> <span class="hljs-string">membership</span> <span class="hljs-string">in</span> <span class="hljs-string">team</span> <span class="hljs-string">$</span>{<span class="hljs-string">team</span>}<span class="hljs-string">:`</span>, <span class="hljs-string">error.message);</span>
                <span class="hljs-string">continue;</span>
              }
            }

            <span class="hljs-string">if</span> <span class="hljs-string">(isTeamMember)</span> {
              <span class="hljs-string">core.setOutput('status'</span>, <span class="hljs-string">'authorized'</span><span class="hljs-string">);</span>
            } <span class="hljs-string">else</span> {
              <span class="hljs-string">console.log('User</span> <span class="hljs-string">not</span> <span class="hljs-string">authorized</span> <span class="hljs-string">to</span> <span class="hljs-string">approve</span> <span class="hljs-string">deployments');</span>
              <span class="hljs-string">core.setOutput('status'</span>, <span class="hljs-string">'unauthorized'</span><span class="hljs-string">);</span>
            }

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Handle</span> <span class="hljs-string">Unauthorized</span> <span class="hljs-string">User</span>
        <span class="hljs-attr">if:</span> <span class="hljs-string">steps.check-approver.outputs.status</span> <span class="hljs-string">==</span> <span class="hljs-string">'unauthorized'</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/github-script@v7</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">script:</span> <span class="hljs-string">|
            const approver = context.payload.comment.user.login;
            await github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.payload.issue.number,
              body: `❌ @${approver} is not authorized to approve deployments. Please wait for approval from an authorized team member.`
            });
            core.setFailed('Approval must come from an authorized user or team member');
</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Extract</span> <span class="hljs-string">commit</span> <span class="hljs-string">SHA</span>
        <span class="hljs-attr">id:</span> <span class="hljs-string">extract-sha</span>
        <span class="hljs-attr">if:</span> <span class="hljs-string">steps.check-approver.outputs.status</span> <span class="hljs-string">==</span> <span class="hljs-string">'authorized'</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/github-script@v7</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">script:</span> <span class="hljs-string">|
            const issueBody = context.payload.issue.body;
            const match = issueBody.match(/"commit_sha":\s*"([a-f0-9]+)"/);
            if (!match) {
              core.setFailed('Could not find commit SHA in issue body');
              return;
            }
            const commitSha = match[1];
            core.setOutput('commit_sha', commitSha);
            console.log(`Extracted commit SHA: ${commitSha}`);
</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v2</span>
        <span class="hljs-attr">if:</span> <span class="hljs-string">steps.check-approver.outputs.status</span> <span class="hljs-string">==</span> <span class="hljs-string">'authorized'</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">ref:</span> <span class="hljs-string">${{</span> <span class="hljs-string">steps.extract-sha.outputs.commit_sha</span> <span class="hljs-string">}}</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Verify</span> <span class="hljs-string">correct</span> <span class="hljs-string">commit</span>
        <span class="hljs-attr">if:</span> <span class="hljs-string">steps.check-approver.outputs.status</span> <span class="hljs-string">==</span> <span class="hljs-string">'authorized'</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">|
          current_sha=$(git rev-parse HEAD)
          expected_sha=${{ steps.extract-sha.outputs.commit_sha }}
          if [ "$current_sha" != "$expected_sha" ]; then
            echo "Error: Checked out SHA ($current_sha) does not match expected SHA ($expected_sha)"
            exit 1
          fi
          echo "Verified correct commit SHA: $current_sha"
</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">to</span> <span class="hljs-string">Staging</span>
        <span class="hljs-attr">if:</span> <span class="hljs-string">steps.check-approver.outputs.status</span> <span class="hljs-string">==</span> <span class="hljs-string">'authorized'</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">|
          echo "Deploying commit ${{ steps.extract-sha.outputs.commit_sha }} to staging..."
          # Add your deployment commands here
</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Close</span> <span class="hljs-string">Approval</span> <span class="hljs-string">Issue</span>
        <span class="hljs-attr">if:</span> <span class="hljs-string">steps.check-approver.outputs.status</span> <span class="hljs-string">==</span> <span class="hljs-string">'authorized'</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/github-script@v7</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">script:</span> <span class="hljs-string">|
            const issue_number = context.payload.issue.number;
            const deployedSha = '${{ steps.extract-sha.outputs.commit_sha }}';
            const approver = context.payload.comment.user.login;
</span>
            <span class="hljs-string">//</span> <span class="hljs-string">Close</span> <span class="hljs-string">the</span> <span class="hljs-string">issue</span>
            <span class="hljs-string">await</span> <span class="hljs-string">github.rest.issues.update({</span>
              <span class="hljs-attr">owner:</span> <span class="hljs-string">context.repo.owner,</span>
              <span class="hljs-attr">repo:</span> <span class="hljs-string">context.repo.repo,</span>
              <span class="hljs-attr">issue_number:</span> <span class="hljs-string">issue_number,</span>
              <span class="hljs-attr">state:</span> <span class="hljs-string">'closed'</span>
            <span class="hljs-string">});</span>

            <span class="hljs-string">//</span> <span class="hljs-string">Add</span> <span class="hljs-string">completion</span> <span class="hljs-string">comment</span>
            <span class="hljs-string">await</span> <span class="hljs-string">github.rest.issues.createComment({</span>
              <span class="hljs-attr">owner:</span> <span class="hljs-string">context.repo.owner,</span>
              <span class="hljs-attr">repo:</span> <span class="hljs-string">context.repo.repo,</span>
              <span class="hljs-attr">issue_number:</span> <span class="hljs-string">issue_number,</span>
              <span class="hljs-attr">body:</span> <span class="hljs-string">`✅</span> <span class="hljs-string">Deployment</span> <span class="hljs-string">to</span> <span class="hljs-string">staging</span> <span class="hljs-string">completed</span> <span class="hljs-string">successfully!\n\nDeployed</span> <span class="hljs-attr">commit:</span> <span class="hljs-string">${deployedSha}\nBranch:</span> <span class="hljs-string">dev\nApproved</span> <span class="hljs-attr">by:</span> <span class="hljs-string">@${approver}`</span>
            <span class="hljs-string">});</span>
</code></pre>
<p>This GitHub Actions workflow automates the deployment of a commit to a staging environment based on approval comments in a GitHub issue. Here's a breakdown of its components:</p>
<hr />
<h3 id="heading-deploy-workflow-explanation">🤖 <strong>Deploy workflow explanation</strong></h3>
<h3 id="heading-trigger-1"><strong>Trigger</strong>:</h3>
<ul>
<li><p><strong>Event</strong>: <code>issue_comment</code> is created.</p>
</li>
<li><p><strong>Condition</strong>: The issue title must contain the phrase <code>"Deploy to Staging needs approval"</code>. The action runs only if this condition is met.</p>
</li>
</ul>
<hr />
<h3 id="heading-permissions-1"><strong>Permissions</strong>:</h3>
<p>The workflow uses:</p>
<ul>
<li><p><code>issues: write</code> (to interact with issues and comments),</p>
</li>
<li><p><code>contents: read</code> (to fetch repository data),</p>
</li>
<li><p><code>pull-requests: read</code>.</p>
</li>
</ul>
<hr />
<h3 id="heading-jobs"><strong>Jobs</strong>:</h3>
<h4 id="heading-1-process-approval">1. <code>process-approval</code>:</h4>
<ul>
<li><p><strong>Runs-on</strong>: <code>ubuntu-latest</code>.</p>
</li>
<li><p><strong>Condition</strong>: The issue must meet the following:</p>
<ul>
<li><p>Title contains <code>"Deploy to Staging needs approval"</code>.</p>
</li>
<li><p>The comment body includes the keywords <code>approve</code> or <code>LGTM</code>.</p>
</li>
</ul>
</li>
</ul>
<hr />
<h4 id="heading-steps-1"><strong>Steps</strong>:</h4>
<ol>
<li><p><strong>Check Approver</strong>:</p>
<ul>
<li><p>Uses the <code>actions/github-script</code> action.</p>
</li>
<li><p>Checks if the commenter:</p>
<ul>
<li><p>Is in the list of <strong>allowed users</strong> (<code>sohag-pro</code>, <code>tech-lead</code>, <code>devops-engineer</code>), or</p>
</li>
<li><p>Belongs to one of the <strong>allowed teams</strong> (<code>devops</code>, <code>senior-developers</code>).</p>
</li>
</ul>
</li>
<li><p>If authorized:</p>
<ul>
<li>Sets the status to <code>authorized</code>.</li>
</ul>
</li>
<li><p>If unauthorized:</p>
<ul>
<li>Adds a comment rejecting the user's approval and fails the job.</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>Handle Unauthorized User</strong>:</p>
<ul>
<li>Posts a rejection comment if the user isn't authorized.</li>
</ul>
</li>
<li><p><strong>Extract Commit SHA</strong>:</p>
<ul>
<li><p>Extracts the <code>commit_sha</code> from the issue body using regex.</p>
</li>
<li><p>Fails if no valid SHA is found.</p>
</li>
</ul>
</li>
<li><p><strong>Checkout the Repository</strong>:</p>
<ul>
<li>Checks out the repository using the extracted <code>commit_sha</code>.</li>
</ul>
</li>
<li><p><strong>Verify Correct Commit</strong>:</p>
<ul>
<li>Ensures the checked-out commit matches the extracted SHA.</li>
</ul>
</li>
<li><p><strong>Deploy to Staging</strong>:</p>
<ul>
<li>Executes deployment commands for the staging environment (placeholder for real deployment logic).</li>
</ul>
</li>
<li><p><strong>Close Approval Issue</strong>:</p>
<ul>
<li><p>Closes the issue and adds a success comment with details:</p>
<ul>
<li><p>Deployed commit SHA,</p>
</li>
<li><p>Branch name,</p>
</li>
<li><p>Approver's GitHub handle.</p>
</li>
</ul>
</li>
</ul>
</li>
</ol>
<hr />
<h3 id="heading-purpose-1"><strong>Purpose</strong>:</h3>
<ul>
<li><p>Ensures controlled deployment to staging by verifying the approver's identity and explicitly approving the commit.</p>
</li>
<li><p>Tracks the deployment process through issue comments and statuses.</p>
</li>
</ul>
<h3 id="heading-key-highlights-1"><strong>Key Highlights</strong>:</h3>
<ul>
<li><p>Implements a strict approval mechanism.</p>
</li>
<li><p>Utilizes team-based and individual-based authorization.</p>
</li>
<li><p>Automatically documents deployment activities in the related issue.</p>
</li>
</ul>
<h2 id="heading-key-benefits">💡 Key Benefits</h2>
<ul>
<li><p><strong>Cost-Effective</strong>: Only pay for actual deployment time</p>
</li>
<li><p><strong>Secure</strong>: Strict access controls</p>
</li>
<li><p><strong>Transparent</strong>: Clear audit trail of who approved what</p>
</li>
<li><p><strong>Flexible</strong>: Easy to customize for your team's needs</p>
</li>
</ul>
<h2 id="heading-real-world-implementation-tips">Real-World Implementation Tips</h2>
<ol>
<li><p>Customize the <code>ALLOWED_APPROVERS</code> and <code>ALLOWED_TEAMS</code></p>
</li>
<li><p>Add more detailed logging for compliance</p>
</li>
<li><p>Consider adding more approval keywords</p>
</li>
<li><p>Implement additional security checks as needed</p>
</li>
</ol>
<h2 id="heading-conclusion">Conclusion</h2>
<p>This workflow demonstrates how a little creativity can solve real DevOps challenges. By thinking outside the traditional CI/CD box, we've created a solution that's not just clever, but genuinely useful.</p>
<h2 id="heading-ready-to-level-up-your-deployment-game">Ready to Level Up Your Deployment Game? 🚀</h2>
<p>Fork the workflows, adapt them to your needs, and watch your deployment process transform!</p>
<p>Would you like me to refine any part of the blog post or add more technical details?</p>
]]></content:encoded></item><item><title><![CDATA[Laravel Best Practices]]></title><description><![CDATA[Laravel Best Practices
1. Database & Eloquent Best Practices
1.1 Optimize Database Queries
// ❌ Bad: N+1 Query Problem
@foreach (Post::all() as $post)
    {{ $post->category->name }}
@endforeach

// ✅ Good: Eager Loading
$posts = Post::with('category...]]></description><link>https://notes.sohag.pro/laravel-best-practices</link><guid isPermaLink="true">https://notes.sohag.pro/laravel-best-practices</guid><category><![CDATA[Laravel]]></category><dc:creator><![CDATA[Sohag Hasan]]></dc:creator><pubDate>Sat, 09 Nov 2024 21:12:34 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1731186719526/635de773-31e9-4aa1-845b-1341379e998c.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-laravel-best-practices">Laravel Best Practices</h1>
<h2 id="heading-1-database-amp-eloquent-best-practices">1. Database &amp; Eloquent Best Practices</h2>
<h3 id="heading-11-optimize-database-queries">1.1 Optimize Database Queries</h3>
<pre><code class="lang-php"><span class="hljs-comment">// ❌ Bad: N+1 Query Problem</span>
@<span class="hljs-keyword">foreach</span> (Post::all() <span class="hljs-keyword">as</span> $post)
    {{ $post-&gt;category-&gt;name }}
@<span class="hljs-keyword">endforeach</span>

<span class="hljs-comment">// ✅ Good: Eager Loading</span>
$posts = Post::with(<span class="hljs-string">'category'</span>)-&gt;get();
@<span class="hljs-keyword">foreach</span> ($posts <span class="hljs-keyword">as</span> $post)
    {{ $post-&gt;category-&gt;name }}
@<span class="hljs-keyword">endforeach</span>

<span class="hljs-comment">// ✅ Even Better: Use Laravel's Lazy Loading when needed</span>
Model::withoutLazy()-&gt;get(); <span class="hljs-comment">// Disable lazy loading in production</span>
</code></pre>
<h3 id="heading-12-use-query-builder-for-complex-queries">1.2 Use Query Builder for Complex Queries</h3>
<pre><code class="lang-php"><span class="hljs-comment">// ✅ Good: Use Query Builder for complex queries</span>
User::query()
    -&gt;select([<span class="hljs-string">'name'</span>, <span class="hljs-string">'email'</span>])
    -&gt;whereHas(<span class="hljs-string">'posts'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">$query</span>) </span>{
        $query-&gt;where(<span class="hljs-string">'published'</span>, <span class="hljs-literal">true</span>);
    })
    -&gt;paginate();
</code></pre>
<h2 id="heading-2-modern-controller-practices">2. Modern Controller Practices</h2>
<h3 id="heading-21-use-invokable-controllers-for-single-action-controllers">2.1 Use Invokable Controllers for Single-Action Controllers</h3>
<pre><code class="lang-php"><span class="hljs-comment">// ✅ Good: Single Action Controller</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ShowDashboardController</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Controller</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__invoke</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword">return</span> view(<span class="hljs-string">'dashboard'</span>, [
            <span class="hljs-string">'metrics'</span> =&gt; <span class="hljs-keyword">$this</span>-&gt;getMetrics(),
        ]);
    }
}
</code></pre>
<h3 id="heading-22-use-form-requests-for-validation">2.2 Use Form Requests for Validation</h3>
<pre><code class="lang-php"><span class="hljs-comment">// ❌ Bad: Validation in Controller</span>
<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">store</span>(<span class="hljs-params">Request $request</span>)
</span>{
    $validated = $request-&gt;validate([
        <span class="hljs-string">'title'</span> =&gt; <span class="hljs-string">'required|max:255'</span>,
        <span class="hljs-string">'body'</span> =&gt; <span class="hljs-string">'required'</span>,
    ]);
}

<span class="hljs-comment">// ✅ Good: Dedicated Form Request</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">StoreArticleRequest</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">FormRequest</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">rules</span>(<span class="hljs-params"></span>): <span class="hljs-title">array</span>
    </span>{
        <span class="hljs-keyword">return</span> [
            <span class="hljs-string">'title'</span> =&gt; [<span class="hljs-string">'required'</span>, <span class="hljs-string">'string'</span>, <span class="hljs-string">'max:255'</span>],
            <span class="hljs-string">'body'</span> =&gt; [<span class="hljs-string">'required'</span>, <span class="hljs-string">'string'</span>],
            <span class="hljs-string">'category_id'</span> =&gt; [<span class="hljs-string">'required'</span>, <span class="hljs-string">'exists:categories,id'</span>],
        ];
    }
}

<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">store</span>(<span class="hljs-params">StoreArticleRequest $request</span>)
</span>{
    $article = Article::create($request-&gt;validated());
}
</code></pre>
<h2 id="heading-3-modern-architecture-patterns">3. Modern Architecture Patterns</h2>
<h3 id="heading-31-use-actions-classes-for-business-logic">3.1 Use Actions Classes for Business Logic</h3>
<pre><code class="lang-php"><span class="hljs-comment">// ✅ Good: Single-Purpose Action Class</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PublishArticleAction</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">execute</span>(<span class="hljs-params">Article $article</span>): <span class="hljs-title">void</span>
    </span>{
        $article-&gt;published_at = now();
        $article-&gt;status = ArticleStatus::Published;
        $article-&gt;save();

        event(<span class="hljs-keyword">new</span> ArticlePublished($article));
    }
}
</code></pre>
<h3 id="heading-32-use-data-transfer-objects-dtos">3.2 Use Data Transfer Objects (DTOs)</h3>
<pre><code class="lang-php"><span class="hljs-comment">// ✅ Good: Use DTOs for complex data structures</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ArticleData</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">
        <span class="hljs-keyword">public</span> readonly <span class="hljs-keyword">string</span> $title,
        <span class="hljs-keyword">public</span> readonly <span class="hljs-keyword">string</span> $content,
        <span class="hljs-keyword">public</span> readonly ?Carbon $publishDate = <span class="hljs-literal">null</span>,
    </span>) </span>{}

    <span class="hljs-keyword">public</span> <span class="hljs-built_in">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fromRequest</span>(<span class="hljs-params">StoreArticleRequest $request</span>): <span class="hljs-title">self</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">self</span>(
            title: $request-&gt;validated(<span class="hljs-string">'title'</span>),
            content: $request-&gt;validated(<span class="hljs-string">'content'</span>),
            publishDate: $request-&gt;validated(<span class="hljs-string">'publish_date'</span>),
        );
    }
}
</code></pre>
<h2 id="heading-4-modern-view-amp-frontend-practices">4. Modern View &amp; Frontend Practices</h2>
<h3 id="heading-41-use-blade-components">4.1 Use Blade Components</h3>
<pre><code class="lang-php"><span class="hljs-comment">// ✅ Good: Reusable Blade Components</span>
<span class="hljs-comment">// alert.blade.php</span>
&lt;x-alert type=<span class="hljs-string">"{{ <span class="hljs-subst">$type</span> }}"</span> :dismissible=<span class="hljs-string">"<span class="hljs-subst">$dismissible</span>"</span>&gt;
    {{ $slot }}
&lt;/x-alert&gt;

<span class="hljs-comment">// Usage</span>
&lt;x-alert type=<span class="hljs-string">"success"</span> :dismissible=<span class="hljs-string">"true"</span>&gt;
    Profile updated successfully!
&lt;/x-alert&gt;
</code></pre>
<h3 id="heading-42-use-laravel-vite-for-asset-management">4.2 Use Laravel Vite for Asset Management</h3>
<pre><code class="lang-php"><span class="hljs-comment">// ✅ Good: Modern Asset Management</span>
<span class="hljs-comment">// vite.config.js</span>
import { defineConfig } <span class="hljs-keyword">from</span> <span class="hljs-string">'vite'</span>;
import laravel <span class="hljs-keyword">from</span> <span class="hljs-string">'laravel-vite-plugin'</span>;

export <span class="hljs-keyword">default</span> defineConfig({
    plugins: [
        laravel({
            input: [<span class="hljs-string">'resources/css/app.css'</span>, <span class="hljs-string">'resources/js/app.js'</span>],
            refresh: <span class="hljs-literal">true</span>,
        }),
    ],
});

<span class="hljs-comment">// In Blade</span>
@vite([<span class="hljs-string">'resources/css/app.css'</span>, <span class="hljs-string">'resources/js/app.js'</span>])
</code></pre>
<h2 id="heading-5-modern-testing-practices">5. Modern Testing Practices</h2>
<h3 id="heading-51-use-pest-for-testing">5.1 Use Pest for Testing</h3>
<pre><code class="lang-php"><span class="hljs-comment">// ✅ Good: Modern Testing with Pest</span>
it(<span class="hljs-string">'creates a new article'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    $response = post(<span class="hljs-string">'/articles'</span>, [
        <span class="hljs-string">'title'</span> =&gt; <span class="hljs-string">'My Article'</span>,
        <span class="hljs-string">'content'</span> =&gt; <span class="hljs-string">'Content here'</span>,
    ]);

    $response-&gt;assertCreated();
    expect(Article::count())-&gt;toBe(<span class="hljs-number">1</span>);
});
</code></pre>
<h3 id="heading-52-use-factories-effectively">5.2 Use Factories Effectively</h3>
<pre><code class="lang-php"><span class="hljs-comment">// ✅ Good: Modern Factory Usage</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ArticleFactory</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Factory</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">published</span>(<span class="hljs-params"></span>): <span class="hljs-title">self</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;state(<span class="hljs-function"><span class="hljs-keyword">fn</span> (<span class="hljs-params"><span class="hljs-keyword">array</span> $attributes</span>) =&gt; [
            '<span class="hljs-title">published_at</span>' =&gt; <span class="hljs-title">now</span>(<span class="hljs-params"></span>),
            '<span class="hljs-title">status</span>' =&gt; <span class="hljs-title">ArticleStatus</span>::<span class="hljs-title">Published</span>,
        ])</span>;
    }
}

<span class="hljs-comment">// Usage</span>
Article::factory()-&gt;published()-&gt;create();
</code></pre>
<h2 id="heading-6-api-development">6. API Development</h2>
<h3 id="heading-61-use-api-resources">6.1 Use API Resources</h3>
<pre><code class="lang-php"><span class="hljs-comment">// ✅ Good: Use API Resources for Response Transformation</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ArticleResource</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">JsonResource</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">toArray</span>(<span class="hljs-params">$request</span>): <span class="hljs-title">array</span>
    </span>{
        <span class="hljs-keyword">return</span> [
            <span class="hljs-string">'id'</span> =&gt; <span class="hljs-keyword">$this</span>-&gt;id,
            <span class="hljs-string">'title'</span> =&gt; <span class="hljs-keyword">$this</span>-&gt;title,
            <span class="hljs-string">'content'</span> =&gt; <span class="hljs-keyword">$this</span>-&gt;when($request-&gt;user()?-&gt;isAdmin(), <span class="hljs-keyword">$this</span>-&gt;content),
            <span class="hljs-string">'created_at'</span> =&gt; <span class="hljs-keyword">$this</span>-&gt;created_at-&gt;toISOString(),
        ];
    }
}
</code></pre>
<h3 id="heading-62-use-sanctum-for-api-authentication">6.2 Use Sanctum for API Authentication</h3>
<pre><code class="lang-php"><span class="hljs-comment">// ✅ Good: Modern API Authentication</span>
Route::middleware([<span class="hljs-string">'auth:sanctum'</span>])-&gt;group(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    Route::apiResource(<span class="hljs-string">'articles'</span>, ArticleController::class);
});
</code></pre>
<h2 id="heading-7-performance-best-practices">7. Performance Best Practices</h2>
<h3 id="heading-71-use-cache-effectively">7.1 Use Cache Effectively</h3>
<pre><code class="lang-php"><span class="hljs-comment">// ✅ Good: Smart Caching</span>
<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">show</span>(<span class="hljs-params">Article $article</span>)
</span>{
    <span class="hljs-keyword">return</span> Cache::remember(<span class="hljs-string">"articles.<span class="hljs-subst">{$article-&gt;id}</span>"</span>, now()-&gt;addHour(), <span class="hljs-function"><span class="hljs-keyword">fn</span> (<span class="hljs-params"></span>) =&gt; 
        <span class="hljs-title">ArticleResource</span>::<span class="hljs-title">make</span>(<span class="hljs-params">$article</span>)
    )</span>;
}
</code></pre>
<h3 id="heading-72-use-queue-for-heavy-tasks">7.2 Use Queue for Heavy Tasks</h3>
<pre><code class="lang-php"><span class="hljs-comment">// ✅ Good: Queue Heavy Operations</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ProcessPodcast</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">ShouldQueue</span>
</span>{
    <span class="hljs-keyword">use</span> <span class="hljs-title">Dispatchable</span>, <span class="hljs-title">InteractsWithQueue</span>, <span class="hljs-title">Queueable</span>, <span class="hljs-title">SerializesModels</span>;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handle</span>(<span class="hljs-params"></span>): <span class="hljs-title">void</span>
    </span>{
        <span class="hljs-comment">// Heavy processing here</span>
    }
}
</code></pre>
<h2 id="heading-8-security-best-practices">8. Security Best Practices</h2>
<h3 id="heading-81-use-policy-classes">8.1 Use Policy Classes</h3>
<pre><code class="lang-php"><span class="hljs-comment">// ✅ Good: Use Policies for Authorization</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ArticlePolicy</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">update</span>(<span class="hljs-params">User $user, Article $article</span>): <span class="hljs-title">bool</span>
    </span>{
        <span class="hljs-keyword">return</span> $user-&gt;id === $article-&gt;user_id || $user-&gt;isAdmin();
    }
}
</code></pre>
<h3 id="heading-82-secure-configuration">8.2 Secure Configuration</h3>
<pre><code class="lang-php"><span class="hljs-comment">// ❌ Bad: Direct Environment Variable Usage</span>
$apiKey = env(<span class="hljs-string">'API_KEY'</span>);

<span class="hljs-comment">// ✅ Good: Use Configuration Files</span>
<span class="hljs-comment">// config/services.php</span>
<span class="hljs-string">'api'</span> =&gt; [
    <span class="hljs-string">'key'</span> =&gt; env(<span class="hljs-string">'API_KEY'</span>),
],

<span class="hljs-comment">// Usage</span>
$apiKey = config(<span class="hljs-string">'services.api.key'</span>);
</code></pre>
<h2 id="heading-9-code-organization">9. Code Organization</h2>
<h3 id="heading-91-use-laravels-directory-structure">9.1 Use Laravel's Directory Structure</h3>
<pre><code class="lang-yaml"><span class="hljs-string">app/</span>
<span class="hljs-string">├──</span> <span class="hljs-string">Actions/</span>         <span class="hljs-comment"># Single-purpose action classes</span>
<span class="hljs-string">├──</span> <span class="hljs-string">Data/</span>            <span class="hljs-comment"># DTOs and other data objects</span>
<span class="hljs-string">├──</span> <span class="hljs-string">Events/</span>          <span class="hljs-comment"># Event classes</span>
<span class="hljs-string">├──</span> <span class="hljs-string">Listeners/</span>       <span class="hljs-comment"># Event listeners</span>
<span class="hljs-string">├──</span> <span class="hljs-string">Services/</span>        <span class="hljs-comment"># Complex business logic</span>
<span class="hljs-string">├──</span> <span class="hljs-string">Http/</span>
<span class="hljs-string">│</span>   <span class="hljs-string">├──</span> <span class="hljs-string">Controllers/</span>
<span class="hljs-string">│</span>   <span class="hljs-string">├──</span> <span class="hljs-string">Middleware/</span>
<span class="hljs-string">│</span>   <span class="hljs-string">└──</span> <span class="hljs-string">Requests/</span>    <span class="hljs-comment"># Form requests</span>
<span class="hljs-string">└──</span> <span class="hljs-string">Models/</span>          <span class="hljs-comment"># Eloquent models</span>
</code></pre>
<h3 id="heading-92-use-service-providers-for-bootstrap-code">9.2 Use Service Providers for Bootstrap Code</h3>
<pre><code class="lang-php"><span class="hljs-comment">// ✅ Good: Register Bindings in Service Provider</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AppServiceProvider</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ServiceProvider</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">register</span>(<span class="hljs-params"></span>): <span class="hljs-title">void</span>
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;app-&gt;singleton(PaymentGateway::class, StripeGateway::class);
    }
}
</code></pre>
<h2 id="heading-10-development-workflow">10. Development Workflow</h2>
<h3 id="heading-101-use-laravel-sail-for-development">10.1 Use Laravel Sail for Development</h3>
<pre><code class="lang-bash"><span class="hljs-comment"># ✅ Good: Use Laravel Sail for consistent development environment</span>
sail up
sail artisan migrate
sail <span class="hljs-built_in">test</span>
</code></pre>
<h3 id="heading-102-use-github-actions-for-cicd">10.2 Use GitHub Actions for CI/CD</h3>
<pre><code class="lang-yaml"><span class="hljs-comment"># ✅ Good: Automated Testing and Deployment</span>
<span class="hljs-attr">name:</span> <span class="hljs-string">Laravel</span>

<span class="hljs-attr">on:</span>
  <span class="hljs-attr">push:</span>
    <span class="hljs-attr">branches:</span> [ <span class="hljs-string">main</span> ]

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">laravel-tests:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-attr">steps:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v2</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Setup</span> <span class="hljs-string">PHP</span>
      <span class="hljs-attr">uses:</span> <span class="hljs-string">shivammathur/setup-php@v2</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Run</span> <span class="hljs-string">Tests</span>
      <span class="hljs-attr">run:</span> <span class="hljs-string">|
        composer install
        php artisan test</span>
</code></pre>
<h1 id="heading-laravel-naming-conventions">Laravel Naming Conventions</h1>
<p>The following table outlines the standard naming conventions for Laravel applications in 2024:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Component</td><td>Convention</td><td>✅ Good Example</td><td>❌ Bad Example</td><td>Notes</td></tr>
</thead>
<tbody>
<tr>
<td>Controller</td><td>singular</td><td><code>PostController</code></td><td><code>PostsController</code></td><td>Use singular form for resource controllers</td></tr>
<tr>
<td>Route</td><td>plural</td><td><code>posts/1</code></td><td><code>post/1</code></td><td>Use plural for resource routes</td></tr>
<tr>
<td>Named route</td><td>snake_case with dots</td><td><a target="_blank" href="http://users.show"><code>users.show</code></a><code>_active</code></td><td><code>show-active-users</code></td><td>Consistent with Laravel's internal naming</td></tr>
<tr>
<td>Model</td><td>singular</td><td><code>User</code></td><td><code>Users</code></td><td>Always use singular for model names</td></tr>
<tr>
<td>hasOne/belongsTo relationship</td><td>singular</td><td><code>postComment</code></td><td><code>postComments</code></td><td>Reflects one-to-one nature</td></tr>
<tr>
<td>Other relationships</td><td>plural</td><td><code>postComments</code></td><td><code>postComment</code></td><td>Reflects one-to-many nature</td></tr>
<tr>
<td>Database table</td><td>plural</td><td><code>post_comments</code></td><td><code>post_comment</code></td><td>Use snake_case, plural form</td></tr>
<tr>
<td>Pivot table</td><td>alphabetical singular models</td><td><code>post_user</code></td><td><code>users_posts</code></td><td>Join singular model names with underscore</td></tr>
<tr>
<td>Model property</td><td>snake_case</td><td><code>$model-&gt;created_at</code></td><td><code>$model-&gt;createdAt</code></td><td>Follow Laravel's convention</td></tr>
<tr>
<td>Foreign key</td><td>singular with _id</td><td><code>post_id</code></td><td><code>PostId</code>, <code>posts_id</code></td><td>Always use snake_case</td></tr>
<tr>
<td>Primary key</td><td>'id'</td><td><code>id</code></td><td><code>custom_id</code></td><td>Stick to Laravel defaults</td></tr>
<tr>
<td>Migration</td><td>datetime_action</td><td><code>2024_01_16_000000_create_posts_table</code></td><td><code>2024_01_16_posts</code></td><td>Include full timestamp</td></tr>
<tr>
<td>Method</td><td>camelCase</td><td><code>getAll()</code></td><td><code>get_all()</code></td><td>Follow PSR-12</td></tr>
<tr>
<td>Resource controller method</td><td>table</td><td><code>store()</code></td><td><code>savePost()</code></td><td>Use standard resource names</td></tr>
<tr>
<td>Variable</td><td>camelCase</td><td><code>$postsWithAuthor</code></td><td><code>$posts_with_creator</code></td><td>Clear and descriptive</td></tr>
<tr>
<td>Collection</td><td>plural, descriptive</td><td><code>$activeUsers</code></td><td><code>$active</code></td><td>Clearly indicate content</td></tr>
<tr>
<td>Object</td><td>singular, descriptive</td><td><code>$activeUser</code></td><td><code>$users</code></td><td>Reflect single instance</td></tr>
<tr>
<td>Config index</td><td>snake_case</td><td><code>articles_enabled</code></td><td><code>ArticlesEnabled</code></td><td>Consistent with Laravel</td></tr>
<tr>
<td>View</td><td>kebab-case</td><td><code>show-filtered.blade.php</code></td><td><code>showFiltered.blade.php</code></td><td>Use hyphens for views</td></tr>
<tr>
<td>Config file</td><td>snake_case</td><td><code>google_calendar.php</code></td><td><code>googleCalendar.php</code></td><td>Use underscores</td></tr>
<tr>
<td>Interface</td><td>adjective/noun</td><td><code>AuthenticationInterface</code></td><td><code>IAuthentication</code></td><td>Follow PSR standards</td></tr>
</tbody>
</table>
</div><h2 id="heading-important-notes-on-naming-conventions">Important Notes on Naming Conventions:</h2>
<ol>
<li><p><strong>Consistency is Key</strong></p>
<ul>
<li><p>Stick to these conventions across your entire application</p>
</li>
<li><p>Use automated tools like PHP CS Fixer to enforce standards</p>
</li>
</ul>
</li>
<li><p><strong>Documentation</strong></p>
<pre><code class="lang-php"> <span class="hljs-comment">// ✅ Good: Clear, consistent naming</span>
 <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PostController</span>
 </span>{
     <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">show</span>(<span class="hljs-params">Post $post</span>)
     </span>{
         <span class="hljs-keyword">return</span> view(<span class="hljs-string">'posts.show'</span>, compact(<span class="hljs-string">'post'</span>));
     }
 }
</code></pre>
</li>
<li><p><strong>File Structure</strong></p>
<pre><code class="lang-plaintext"> app/
 ├── Http/
 │   └── Controllers/
 │       └── PostController.php
 ├── Models/
 │   └── Post.php
 └── Views/
     └── posts/
         └── show-details.blade.php
</code></pre>
</li>
<li><p><strong>Database Conventions</strong></p>
<pre><code class="lang-php"> <span class="hljs-comment">// ✅ Good: Migration naming</span>
 <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CreatePostCommentsTable</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Migration</span>
 </span>{
     <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">up</span>(<span class="hljs-params"></span>)
     </span>{
         Schema::create(<span class="hljs-string">'post_comments'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">Blueprint $table</span>) </span>{
             $table-&gt;id();
             $table-&gt;foreignId(<span class="hljs-string">'post_id'</span>)-&gt;constrained();
             $table-&gt;timestamps();
         });
     }
 }
</code></pre>
</li>
<li><p><strong>Relationship Naming</strong></p>
<pre><code class="lang-php"> <span class="hljs-comment">// ✅ Good: Clear relationship naming</span>
 <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Post</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Model</span>
 </span>{
     <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">comments</span>(<span class="hljs-params"></span>)
     </span>{
         <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;hasMany(Comment::class);
     }

     <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">author</span>(<span class="hljs-params"></span>)
     </span>{
         <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;belongsTo(User::class, <span class="hljs-string">'user_id'</span>);
     }
 }
</code></pre>
</li>
</ol>
<p>Following these naming conventions helps maintain consistency across your Laravel application and makes it easier for other developers to understand and work with your code. It also aligns with Laravel's built-in conventions, ensuring better integration with the framework's features and functionality.</p>
<p><strong>Remember to:</strong></p>
<ul>
<li><p>Use PHP 8.2+ features where appropriate</p>
</li>
<li><p>Keep dependencies updated</p>
</li>
<li><p>Follow PSR-12 coding standards</p>
</li>
<li><p>Use static analysis tools like PHPStan</p>
</li>
<li><p>Implement proper logging and monitoring</p>
</li>
<li><p>Use Laravel Horizon for queue monitoring</p>
</li>
<li><p>Implement proper error handling and logging</p>
</li>
<li><p>Use Laravel Telescope for debugging in development</p>
</li>
</ul>
<p>These practices reflect modern Laravel development as of 2024, incorporating new features and best practices from recent Laravel versions.</p>
]]></content:encoded></item><item><title><![CDATA[Understanding Code Smells in PHP and Laravel: A Beginner's Guide]]></title><description><![CDATA[Code Smells in PHP and Laravel
Ever walked into a room and immediately noticed something was off? Maybe it was a faint burning smell from the kitchen or the sound of a washing machine that didn't quite seem right. These warning signs in our daily liv...]]></description><link>https://notes.sohag.pro/understanding-code-smells-in-php-and-laravel-a-beginners-guide</link><guid isPermaLink="true">https://notes.sohag.pro/understanding-code-smells-in-php-and-laravel-a-beginners-guide</guid><category><![CDATA[code smell ]]></category><category><![CDATA[Laravel]]></category><category><![CDATA[PHP]]></category><dc:creator><![CDATA[Sohag Hasan]]></dc:creator><pubDate>Sat, 09 Nov 2024 20:56:25 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1731185735043/fd5a450f-1a2b-4ee4-8521-9adba7c35c6d.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-code-smells-in-php-and-laravel">Code Smells in PHP and Laravel</h1>
<p>Ever walked into a room and immediately noticed something was off? Maybe it was a faint burning smell from the kitchen or the sound of a washing machine that didn't quite seem right. These warning signs in our daily lives are similar to what developers call "code smells" in programming—hints that something in our code needs attention.</p>
<h2 id="heading-what-are-code-smells">What Are Code Smells?</h2>
<p>Code smells are warning signs in our code that suggest deeper problems. They're not bugs—the code might work perfectly fine—but they indicate areas where your code could be cleaner, more efficient, or easier to maintain.</p>
<p>Think of it like a cluttered garage. Everything works and you can still park your car, but finding your tools takes longer than it should, and adding new items becomes increasingly difficult. That's exactly how code with "smells" feels to work with.</p>
<h2 id="heading-common-code-smells-in-php-and-laravel-and-how-to-fix-them">Common Code Smells in PHP and Laravel (And How to Fix Them)</h2>
<h3 id="heading-1-the-long-method-smell">1. The Long Method Smell</h3>
<p>This is like trying to read an instruction manual with no chapters or sections—it's overwhelming and hard to follow.</p>
<h4 id="heading-before-smelly-code">Before (Smelly Code):</h4>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">processOrder</span>(<span class="hljs-params">$orderId</span>)
</span>{
    $order = Order::find($orderId);

    <span class="hljs-comment">// Validate order</span>
    <span class="hljs-keyword">if</span> (!$order) {
        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Exception</span>(<span class="hljs-string">'Order not found'</span>);
    }

    <span class="hljs-comment">// Check inventory</span>
    <span class="hljs-keyword">foreach</span> ($order-&gt;items <span class="hljs-keyword">as</span> $item) {
        $product = Product::find($item-&gt;product_id);
        <span class="hljs-keyword">if</span> ($product-&gt;stock &lt; $item-&gt;quantity) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Exception</span>(<span class="hljs-string">'Insufficient stock'</span>);
        }
    }

    <span class="hljs-comment">// Update inventory</span>
    <span class="hljs-keyword">foreach</span> ($order-&gt;items <span class="hljs-keyword">as</span> $item) {
        $product = Product::find($item-&gt;product_id);
        $product-&gt;stock -= $item-&gt;quantity;
        $product-&gt;save();
    }

    <span class="hljs-comment">// Process payment</span>
    $payment = <span class="hljs-keyword">new</span> Payment();
    $payment-&gt;amount = $order-&gt;total;
    $payment-&gt;order_id = $order-&gt;id;
    $payment-&gt;process();

    <span class="hljs-comment">// Send email</span>
    Mail::to($order-&gt;user-&gt;email)-&gt;send(<span class="hljs-keyword">new</span> OrderConfirmation($order));

    <span class="hljs-comment">// Update order status</span>
    $order-&gt;status = <span class="hljs-string">'processed'</span>;
    $order-&gt;save();
}
</code></pre>
<h4 id="heading-after-clean-code">After (Clean Code):</h4>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">processOrder</span>(<span class="hljs-params">$orderId</span>)
</span>{
    $order = <span class="hljs-keyword">$this</span>-&gt;findOrder($orderId);
    <span class="hljs-keyword">$this</span>-&gt;validateInventory($order);
    <span class="hljs-keyword">$this</span>-&gt;updateInventory($order);
    <span class="hljs-keyword">$this</span>-&gt;processPayment($order);
    <span class="hljs-keyword">$this</span>-&gt;sendConfirmation($order);
    <span class="hljs-keyword">$this</span>-&gt;updateOrderStatus($order);
}

<span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">findOrder</span>(<span class="hljs-params">$orderId</span>)
</span>{
    $order = Order::findOrFail($orderId);
    <span class="hljs-keyword">return</span> $order;
}

<span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">validateInventory</span>(<span class="hljs-params">Order $order</span>)
</span>{
    <span class="hljs-keyword">foreach</span> ($order-&gt;items <span class="hljs-keyword">as</span> $item) {
        <span class="hljs-keyword">if</span> ($item-&gt;product-&gt;stock &lt; $item-&gt;quantity) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Exception</span>(<span class="hljs-string">'Insufficient stock'</span>);
        }
    }
}

<span class="hljs-comment">// Additional methods...</span>
</code></pre>
<h3 id="heading-2-the-duplicate-code-smell">2. The Duplicate Code Smell</h3>
<p>Imagine having the same house key copied five times—if you need to change the lock, you'll have to replace all five keys. That's the problem with code duplication.</p>
<h4 id="heading-before-smelly-code-1">Before (Smelly Code):</h4>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">calculateTotalPrice</span>(<span class="hljs-params">$items</span>)
</span>{
    $total = <span class="hljs-number">0</span>;
    <span class="hljs-keyword">foreach</span> ($items <span class="hljs-keyword">as</span> $item) {
        $price = $item-&gt;price;
        $tax = $price * <span class="hljs-number">0.2</span>;
        $shipping = $price &gt; <span class="hljs-number">100</span> ? <span class="hljs-number">0</span> : <span class="hljs-number">10</span>;
        $total += $price + $tax + $shipping;
    }
    <span class="hljs-keyword">return</span> $total;
}

<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">calculateDiscountedPrice</span>(<span class="hljs-params">$items</span>)
</span>{
    $total = <span class="hljs-number">0</span>;
    <span class="hljs-keyword">foreach</span> ($items <span class="hljs-keyword">as</span> $item) {
        $price = $item-&gt;price;
        $tax = $price * <span class="hljs-number">0.2</span>;
        $shipping = $price &gt; <span class="hljs-number">100</span> ? <span class="hljs-number">0</span> : <span class="hljs-number">10</span>;
        $discount = $price * <span class="hljs-number">0.1</span>;
        $total += $price + $tax + $shipping - $discount;
    }
    <span class="hljs-keyword">return</span> $total;
}
</code></pre>
<h4 id="heading-after-clean-code-1">After (Clean Code):</h4>
<pre><code class="lang-php"><span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">calculateBasePrice</span>(<span class="hljs-params">$item</span>)
</span>{
    $price = $item-&gt;price;
    $tax = $price * <span class="hljs-number">0.2</span>;
    $shipping = $price &gt; <span class="hljs-number">100</span> ? <span class="hljs-number">0</span> : <span class="hljs-number">10</span>;
    <span class="hljs-keyword">return</span> $price + $tax + $shipping;
}

<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">calculateTotalPrice</span>(<span class="hljs-params">$items</span>)
</span>{
    <span class="hljs-keyword">return</span> collect($items)-&gt;sum(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">$item</span>) </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;calculateBasePrice($item);
    });
}

<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">calculateDiscountedPrice</span>(<span class="hljs-params">$items</span>)
</span>{
    <span class="hljs-keyword">return</span> collect($items)-&gt;sum(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">$item</span>) </span>{
        $basePrice = <span class="hljs-keyword">$this</span>-&gt;calculateBasePrice($item);
        <span class="hljs-keyword">return</span> $basePrice - ($item-&gt;price * <span class="hljs-number">0.1</span>);
    });
}
</code></pre>
<h3 id="heading-3-the-god-object-smell">3. The God Object Smell</h3>
<p>This is like having one kitchen drawer that holds everything from utensils to receipts to batteries. In Laravel, it often manifests as a model that knows too much and does too much.</p>
<h4 id="heading-before-smelly-code-2">Before (Smelly Code):</h4>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Model</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">processOrder</span>(<span class="hljs-params">$items</span>)
    </span>{
        <span class="hljs-comment">// Order processing logic</span>
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">calculateTaxes</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-comment">// Tax calculation logic</span>
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sendWelcomeEmail</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-comment">// Email logic</span>
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">generateInvoice</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-comment">// Invoice generation logic</span>
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updateShippingAddress</span>(<span class="hljs-params">$address</span>)
    </span>{
        <span class="hljs-comment">// Address update logic</span>
    }
}
</code></pre>
<h4 id="heading-after-clean-code-2">After (Clean Code):</h4>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Model</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">orders</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;hasMany(Order::class);
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">OrderProcessor</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">process</span>(<span class="hljs-params">User $user, <span class="hljs-keyword">array</span> $items</span>)
    </span>{
        <span class="hljs-comment">// Order processing logic</span>
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TaxCalculator</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">calculate</span>(<span class="hljs-params">User $user</span>)
    </span>{
        <span class="hljs-comment">// Tax calculation logic</span>
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserMailer</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sendWelcome</span>(<span class="hljs-params">User $user</span>)
    </span>{
        <span class="hljs-comment">// Email logic</span>
    }
}
</code></pre>
<h2 id="heading-why-it-matters">Why It Matters</h2>
<p>Addressing code smells isn't just about being pedantic—it has real, practical benefits:</p>
<ol>
<li><p><strong>Reduced Bug Risk</strong>: Cleaner code means fewer hiding places for bugs. When each piece of code has a single, clear responsibility, problems are easier to spot and fix.</p>
</li>
<li><p><strong>Easier Maintenance</strong>: Think of clean code like a well-organized toolbox. When you need to fix something, you know exactly where to look.</p>
</li>
<li><p><strong>Better Team Collaboration</strong>: New team members can understand and work with clean code more quickly, reducing onboarding time and friction.</p>
</li>
<li><p><strong>Lower Technical Debt</strong>: By addressing code smells early, you prevent small issues from snowballing into major refactoring projects.</p>
</li>
</ol>
<h2 id="heading-laravel-specific-tips">Laravel-Specific Tips</h2>
<ol>
<li><p>Use Laravel's built-in tools to fight code smells:</p>
<ul>
<li><p>Leverage Service Providers for dependency injection</p>
</li>
<li><p>Use Form Requests for validation logic</p>
</li>
<li><p>Implement Jobs for complex processing</p>
</li>
<li><p>Utilize Events and Listeners for decoupling</p>
</li>
</ul>
</li>
<li><p>Follow Laravel's conventions:</p>
</li>
</ol>
<pre><code class="lang-php"><span class="hljs-comment">// Instead of this:</span>
<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">get_user_posts</span>(<span class="hljs-params">$user_id</span>)

// <span class="hljs-title">Do</span> <span class="hljs-title">this</span>:
<span class="hljs-title">public</span> <span class="hljs-title">function</span> <span class="hljs-title">getUserPosts</span>(<span class="hljs-params">$userId</span>)</span>
</code></pre>
<h2 id="heading-key-takeaways">Key Takeaways</h2>
<ol>
<li><p>Code smells are warning signs, not errors. They indicate areas where your code could be improved.</p>
</li>
<li><p>Regular refactoring is like regular house cleaning—it's easier to maintain cleanliness than to deal with accumulated mess.</p>
</li>
<li><p>Use Laravel's built-in features and conventions to write cleaner code from the start.</p>
</li>
<li><p>When in doubt, follow the Single Responsibility Principle: each class and method should do one thing and do it well.</p>
</li>
</ol>
<h2 id="heading-getting-started">Getting Started</h2>
<p>Begin your code cleanup journey by:</p>
<ol>
<li><p>Reviewing one piece of code at a time</p>
</li>
<li><p>Looking for the smells we've discussed</p>
</li>
<li><p>Making small, incremental improvements</p>
</li>
<li><p>Running tests after each change</p>
</li>
<li><p>Committing improvements regularly</p>
</li>
</ol>
<p>Remember, perfect code doesn't exist, but better code always does. Start small, be consistent, and gradually build better coding habits. Your future self (and your teammates) will thank you!</p>
]]></content:encoded></item><item><title><![CDATA[Understanding Laravel Macros: A Beginner's Guide]]></title><description><![CDATA[Understanding Laravel Macros
Have you ever wished you could add your own special features to Laravel's built-in functions? That's exactly what Laravel macros let you do! Think of macros as custom add-ons that enhance Laravel's capabilities without me...]]></description><link>https://notes.sohag.pro/understanding-laravel-macros-a-beginners-guide</link><guid isPermaLink="true">https://notes.sohag.pro/understanding-laravel-macros-a-beginners-guide</guid><category><![CDATA[Laravel]]></category><category><![CDATA[PHP]]></category><dc:creator><![CDATA[Sohag Hasan]]></dc:creator><pubDate>Sat, 09 Nov 2024 20:46:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1731185116596/e05732f9-5efd-4f92-8b1c-6ed310723c62.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-understanding-laravel-macros">Understanding Laravel Macros</h1>
<p>Have you ever wished you could add your own special features to Laravel's built-in functions? That's exactly what Laravel macros let you do! Think of macros as custom add-ons that enhance Laravel's capabilities without messing with its core code. In this guide, we'll explore what macros are, how they work, and why they're so useful.</p>
<h2 id="heading-what-are-laravel-macros">What Are Laravel Macros?</h2>
<p>Imagine you have a Swiss Army knife. It comes with several useful tools like a knife, scissors, and screwdriver. Now, what if you could add your own custom tools to that Swiss Army knife without taking it apart? That's essentially what Laravel macros do for your code – they let you add new methods to existing Laravel classes.</p>
<h2 id="heading-real-world-example">Real-World Example</h2>
<p>Let's say you frequently need to convert prices from one currency to another in your application. Instead of writing the same conversion code repeatedly, you could create a macro that adds a <code>toCurrency</code> method to Laravel's Collection class:</p>
<pre><code class="lang-php">Collection::macro(<span class="hljs-string">'toCurrency'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">$from = <span class="hljs-string">'USD'</span>, $to = <span class="hljs-string">'EUR'</span></span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;map(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">$amount</span>) <span class="hljs-title">use</span> (<span class="hljs-params">$from, $to</span>) </span>{
        <span class="hljs-comment">// Simple conversion logic for demonstration</span>
        $rate = <span class="hljs-number">0.85</span>; <span class="hljs-comment">// USD to EUR conversion rate</span>
        <span class="hljs-keyword">return</span> $amount * $rate;
    });
});
</code></pre>
<p>Now you can use it like this:</p>
<pre><code class="lang-php">$prices = collect([<span class="hljs-number">10</span>, <span class="hljs-number">20</span>, <span class="hljs-number">30</span>]);
$euroPrices = $prices-&gt;toCurrency(<span class="hljs-string">'USD'</span>, <span class="hljs-string">'EUR'</span>);
<span class="hljs-comment">// Result: [8.5, 17, 25.5]</span>
</code></pre>
<h2 id="heading-creating-your-first-macro">Creating Your First Macro</h2>
<p>Setting up a macro is straightforward. Here's how to do it step by step:</p>
<ol>
<li><p>Choose where to register your macro. The best place is usually in a service provider.</p>
</li>
<li><p>Create a new service provider if needed:</p>
<pre><code class="lang-bash"> php artisan make:provider MacroServiceProvider
</code></pre>
</li>
<li><p>Register your macro in the boot method:</p>
</li>
</ol>
<pre><code class="lang-php"><span class="hljs-keyword">namespace</span> <span class="hljs-title">App</span>\<span class="hljs-title">Providers</span>;

<span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Support</span>\<span class="hljs-title">Collection</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Support</span>\<span class="hljs-title">ServiceProvider</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MacroServiceProvider</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ServiceProvider</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">boot</span>(<span class="hljs-params"></span>)
    </span>{
        Collection::macro(<span class="hljs-string">'uppercase'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;map(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">$value</span>) </span>{
                <span class="hljs-keyword">return</span> strtoupper($value);
            });
        });
    }
}
</code></pre>
<ol start="4">
<li>Add your service provider to <code>config/app.php</code>:</li>
</ol>
<pre><code class="lang-php"><span class="hljs-string">'providers'</span> =&gt; [
    <span class="hljs-comment">// Other providers...</span>
    App\Providers\MacroServiceProvider::class,
],
</code></pre>
<h2 id="heading-when-to-use-macros">When to Use Macros</h2>
<p>Macros are perfect for:</p>
<ul>
<li><p>Adding commonly used functionality across your application</p>
</li>
<li><p>Extending Laravel's built-in classes with custom methods</p>
</li>
<li><p>Keeping your code DRY (Don't Repeat Yourself)</p>
</li>
<li><p>Creating domain-specific helper methods</p>
</li>
</ul>
<h2 id="heading-the-importance-of-macros">The Importance of Macros</h2>
<h3 id="heading-1-code-reusability">1. Code Reusability</h3>
<p>Instead of copying and pasting the same code in multiple places, macros let you define the functionality once and use it everywhere. This makes your code more maintainable and reduces the chance of errors.</p>
<h3 id="heading-2-clean-code">2. Clean Code</h3>
<p>Macros help keep your code clean and organized. Instead of cluttering your controllers or models with utility methods, you can encapsulate common functionality in macros.</p>
<h3 id="heading-3-consistent-api">3. Consistent API</h3>
<p>By using macros, you maintain a consistent API throughout your application. Your custom methods become part of Laravel's fluent interface, making your code more readable and intuitive.</p>
<h3 id="heading-4-easy-testing">4. Easy Testing</h3>
<p>Macros can be easily tested in isolation, making your test suite more reliable and focused.</p>
<h2 id="heading-best-practices">Best Practices</h2>
<ol>
<li><p><strong>Name Clearly</strong>: Give your macros descriptive names that clearly indicate their purpose.</p>
</li>
<li><p><strong>Keep it Simple</strong>: Each macro should do one thing and do it well.</p>
</li>
<li><p><strong>Document Well</strong>: Add PHPDoc blocks to document your macros' parameters and return types.</p>
</li>
<li><p><strong>Test Thoroughly</strong>: Write unit tests for your macros to ensure they work as expected.</p>
</li>
</ol>
<h2 id="heading-practical-example-date-formatting-macro">Practical Example: Date Formatting Macro</h2>
<p>Here's a practical example of a macro that adds a custom date formatting method to Laravel's Carbon date handling:</p>
<pre><code class="lang-php"><span class="hljs-keyword">use</span> <span class="hljs-title">Carbon</span>\<span class="hljs-title">Carbon</span>;

Carbon::macro(<span class="hljs-string">'formatForHumans'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">$this</span>-&gt;isToday()) {
        <span class="hljs-keyword">return</span> <span class="hljs-string">'Today at '</span> . <span class="hljs-keyword">$this</span>-&gt;format(<span class="hljs-string">'H:i'</span>);
    }
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">$this</span>-&gt;isYesterday()) {
        <span class="hljs-keyword">return</span> <span class="hljs-string">'Yesterday at '</span> . <span class="hljs-keyword">$this</span>-&gt;format(<span class="hljs-string">'H:i'</span>);
    }
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;format(<span class="hljs-string">'M d, Y H:i'</span>);
});
</code></pre>
<p>Now you can use it anywhere in your application:</p>
<pre><code class="lang-php">$date = Carbon::now();
<span class="hljs-keyword">echo</span> $date-&gt;formatForHumans(); <span class="hljs-comment">// "Today at 14:30"</span>
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Laravel macros are powerful tools that allow you to extend Laravel's functionality in a clean and maintainable way. They help you write more efficient code by:</p>
<ul>
<li><p>Reducing code duplication</p>
</li>
<li><p>Providing a consistent API</p>
</li>
<li><p>Making your code more readable and maintainable</p>
</li>
<li><p>Allowing for easy testing</p>
</li>
</ul>
<p>As you continue your Laravel journey, remember that macros are there to help you customize and extend the framework to better suit your needs. Start small with simple macros, and as you get more comfortable, you can create more complex ones to handle your specific use cases.</p>
<p>Remember: The best macro is one that solves a real problem in your application while making your code cleaner and more maintainable. Happy coding! 🚀</p>
]]></content:encoded></item><item><title><![CDATA[Setting Up Your Web Server in Minutes: A Beginner's Guide]]></title><description><![CDATA[Setting Up Your Web Server in Minutes
TL;DR: Want to set up a complete web server for your Laravel project without the headache? Just copy-paste a single command, answer a few simple questions, and you're done! It's like having a tech expert do all t...]]></description><link>https://notes.sohag.pro/setting-up-your-web-server-in-minutes-a-beginners-guide</link><guid isPermaLink="true">https://notes.sohag.pro/setting-up-your-web-server-in-minutes-a-beginners-guide</guid><category><![CDATA[vps server]]></category><category><![CDATA[PHP]]></category><category><![CDATA[Laravel]]></category><dc:creator><![CDATA[Sohag Hasan]]></dc:creator><pubDate>Fri, 08 Nov 2024 23:28:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1731108320984/685bde5b-eb25-4b69-ba05-267b9852c3ba.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-setting-up-your-web-server-in-minutes">Setting Up Your Web Server in Minutes</h1>
<p><strong>TL;DR</strong>: Want to set up a complete web server for your Laravel project without the headache? Just copy-paste a single command, answer a few simple questions, and you're done! It's like having a tech expert do all the heavy lifting for you.</p>
<p>Command: <code>/bin/bash -c "$(curl -fsSL</code> <a target="_blank" href="https://raw.githubusercontent.com/sohag-pro/SingleCommand/main/lamp.sh"><code>https://raw.githubusercontent.com/sohag-pro/SingleCommand/main/lamp.sh</code></a><code>)"</code></p>
<p>Github: <a target="_blank" href="https://github.com/sohag-pro/SingleCommand">https://github.com/sohag-pro/SingleCommand</a></p>
<h2 id="heading-why-this-matters">Why This Matters</h2>
<p>Picture this: You've just finished building an awesome web application, and now you need to share it with the world. But wait – setting up a server feels like assembling furniture without instructions, in the dark, while wearing mittens. You need to install Apache, PHP, MySQL, Node.js, and configure them all to work together. It's enough to make anyone's head spin!</p>
<p>That's where this magical little script comes in. It's like having a tech-savvy friend who knows exactly what to do and handles all the complicated stuff for you. Instead of spending hours googling commands and troubleshooting errors, you can have your server ready in about the same time it takes to brew a cup of coffee.</p>
<h2 id="heading-what-does-it-actually-do">What Does It Actually Do?</h2>
<p>This script sets up what we call a "LAMP stack" (Linux, Apache, MySQL, PHP) along with some extra goodies that modern web development needs. Think of it as preparing a complete kitchen for a chef:</p>
<ul>
<li><p><strong>Apache</strong>: Your restaurant's front door – it serves your website to visitors</p>
</li>
<li><p><strong>MySQL</strong>: Your pantry – stores all your application's data</p>
</li>
<li><p><strong>PHP</strong>: Your chef – processes all the requests and creates dynamic content</p>
</li>
<li><p><strong>Node.js</strong>: Your sous chef – helps with modern JavaScript tools</p>
</li>
<li><p><strong>Extra utilities</strong>: Various helpful tools like Git, Composer, and optionally Yarn and PM2</p>
</li>
</ul>
<h2 id="heading-how-to-use-it">How to Use It</h2>
<h3 id="heading-prerequisites">Prerequisites</h3>
<p>Before you begin, make sure you have:</p>
<ul>
<li><p>A fresh Ubuntu 22.04 LTS server</p>
</li>
<li><p>Admin (sudo) access</p>
</li>
<li><p>An internet connection</p>
</li>
<li><p>5 minutes of free time</p>
</li>
<li><p>Optional: A domain name if you want your site available at yourdomain.com</p>
</li>
</ul>
<h3 id="heading-step-by-step-guide">Step-by-Step Guide</h3>
<ol>
<li>Open your terminal and paste this command:</li>
</ol>
<pre><code class="lang-bash">/bin/bash -c <span class="hljs-string">"<span class="hljs-subst">$(curl -fsSL https://raw.githubusercontent.com/sohag-pro/SingleCommand/main/lamp.sh)</span>"</span>
</code></pre>
<ol start="2">
<li><p>The script will then ask you a few simple questions:</p>
<ul>
<li><p>Which PHP version you want (7.4 through 8.4)</p>
</li>
<li><p>Your preferred MySQL username and password</p>
</li>
<li><p>Which version of Node.js you'd like</p>
</li>
<li><p>Whether you want extra tools like Yarn and PM2</p>
</li>
<li><p>Your GitHub repository URL</p>
</li>
<li><p>Your domain name</p>
</li>
</ul>
</li>
</ol>
<p>That's it! The script handles everything else automatically.</p>
<h2 id="heading-what-makes-this-special">What Makes This Special?</h2>
<ol>
<li><p><strong>Time-Saving</strong>: What usually takes hours of manual setup is reduced to minutes</p>
</li>
<li><p><strong>Error-Proof</strong>: No more typos in commands or forgotten steps</p>
</li>
<li><p><strong>Customizable</strong>: Choose your preferred versions of PHP and Node.js</p>
</li>
<li><p><strong>Secure</strong>: Properly sets up permissions and security configurations</p>
</li>
<li><p><strong>Complete</strong>: Includes everything you need for a modern Laravel application</p>
</li>
</ol>
<h2 id="heading-real-world-example">Real-World Example</h2>
<p>Imagine you're a developer who just finished a client's website. Instead of:</p>
<ul>
<li><p>Spending 2 hours installing and configuring packages</p>
</li>
<li><p>Googling "how to set up Apache virtual hosts"</p>
</li>
<li><p>Debugging MySQL permission issues</p>
</li>
<li><p>Fighting with SSL certificate installation</p>
</li>
</ul>
<p>You can just run one command, answer a few questions, and spend those saved hours actually working on your project (or maybe taking a well-deserved break!).</p>
<h2 id="heading-best-practices-and-tips">Best Practices and Tips</h2>
<ul>
<li><p>Always run this on a fresh Ubuntu 22.04 installation</p>
</li>
<li><p>Have your GitHub repository URL ready</p>
</li>
<li><p>If you're using a domain name, set up your DNS A record before installing SSL</p>
</li>
<li><p>Keep your MySQL credentials somewhere safe</p>
</li>
<li><p>Make sure your repository has both <code>.env.example</code> and <code>composer.json</code> files</p>
</li>
</ul>
<h2 id="heading-in-conclusion">In Conclusion</h2>
<p>Server setup doesn't have to be complicated or time-consuming. This script turns what used to be a daunting task into something as simple as ordering takeout. Whether you're a seasoned developer tired of repetitive setup tasks or a beginner intimidated by server configuration, this tool helps you get up and running quickly and reliably.</p>
<p>Remember: good tools should make your life easier, not harder. This script does exactly that – it handles the complex technical details so you can focus on what really matters: building great web applications.</p>
<p>Ready to try it out? Grab a coffee, run the command, and watch as your server sets itself up. Happy coding! 🚀</p>
]]></content:encoded></item><item><title><![CDATA[Introduction to PHP Performance Monitoring]]></title><description><![CDATA[PHP Performance Monitoring
As a PHP developer, ensuring the performance and reliability of your applications is crucial, especially in high-traffic or resource-intensive environments. Performance monitoring allows you to identify bottlenecks, optimiz...]]></description><link>https://notes.sohag.pro/introduction-to-php-performance-monitoring</link><guid isPermaLink="true">https://notes.sohag.pro/introduction-to-php-performance-monitoring</guid><category><![CDATA[Performance Monitoring]]></category><category><![CDATA[PHP]]></category><dc:creator><![CDATA[Sohag Hasan]]></dc:creator><pubDate>Tue, 05 Nov 2024 22:25:47 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1730845628908/c8bc334c-9027-4992-a9dc-b76b8ca07e93.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-php-performance-monitoring">PHP Performance Monitoring</h2>
<p>As a PHP developer, ensuring the performance and reliability of your applications is crucial, especially in high-traffic or resource-intensive environments. Performance monitoring allows you to identify bottlenecks, optimize resource usage, and provide a seamless user experience for your customers. In this beginner-friendly blog post, we'll explore the essentials of PHP performance monitoring, popular tools and techniques, and best practices for troubleshooting and optimizing your application's performance.</p>
<h2 id="heading-understanding-performance-metrics">Understanding Performance Metrics</h2>
<p>Performance monitoring revolves around various metrics that provide insights into the health and efficiency of your application. Some of the key metrics you'll want to track include:</p>
<ol>
<li><p><strong>Response Time</strong>: The time it takes for your application to respond to a user's request. This is a crucial metric that directly impacts user experience.</p>
</li>
<li><p><strong>CPU Utilization</strong>: The percentage of available CPU resources being used by your application. High CPU usage can indicate inefficient code or resource-intensive processes.</p>
</li>
<li><p><strong>Memory Usage</strong>: The amount of RAM being consumed by your application. Excessive memory usage can lead to performance degradation and potentially crash your application.</p>
</li>
<li><p><strong>Database Queries</strong>: The number and execution time of database queries made by your application. Inefficient queries can significantly impact performance.</p>
</li>
<li><p><strong>Error Rates</strong>: The frequency and types of errors occurring in your application, which can help identify problematic areas.</p>
</li>
</ol>
<p>By monitoring these metrics, you can gain a comprehensive understanding of your application's performance and identify areas that need optimization.</p>
<h2 id="heading-popular-php-performance-monitoring-tools">Popular PHP Performance Monitoring Tools</h2>
<p>To effectively monitor the performance of your PHP application, there are several popular tools and techniques you can leverage:</p>
<ol>
<li><p><strong>New Relic</strong>: New Relic is a widely used application performance monitoring (APM) tool that provides detailed insights into your application's performance, including transaction tracing, database monitoring, and error reporting.</p>
</li>
<li><p><strong>Blackfire</strong>: Blackfire is a powerful profiling tool that helps you identify performance bottlenecks in your PHP code. It provides detailed profiling information, including CPU and memory usage, as well as recommendations for optimizations.</p>
</li>
<li><p><strong>Xdebug</strong>: Xdebug is a PHP extension that enables advanced debugging and profiling capabilities. It can help you analyze code execution, identify slow-running functions, and pinpoint the root causes of performance issues.</p>
</li>
<li><p><strong>PHP Caching</strong>: Implementing caching mechanisms, such as Memcached or Redis, can significantly improve the performance of your PHP application by reducing the load on your database and server resources.</p>
</li>
<li><p><strong>PHP Profiling</strong>: Using built-in PHP profiling tools, such as Xdebug or the built-in profiler, can help you identify performance bottlenecks and optimize your code.</p>
</li>
</ol>
<p>Let's dive into setting up and using some of these tools:</p>
<h3 id="heading-setting-up-new-relic">Setting up New Relic</h3>
<ol>
<li><p>Sign up for a New Relic account and install the New Relic PHP agent on your server.</p>
</li>
<li><p>Configure the agent by updating your <code>php.ini</code> file with the necessary settings.</p>
</li>
<li><p>Restart your web server, and you'll start seeing performance data in the New Relic dashboard.</p>
</li>
<li><p>Analyze the dashboard to identify slow transactions, database queries, and other performance issues.</p>
</li>
</ol>
<h3 id="heading-profiling-with-blackfire">Profiling with Blackfire</h3>
<ol>
<li><p>Install the Blackfire agent and probe on your server.</p>
</li>
<li><p>Configure the probe by updating your <code>php.ini</code> file with the necessary settings.</p>
</li>
<li><p>Run your application and use the Blackfire web interface or command-line tool to collect performance data.</p>
</li>
<li><p>Analyze the profiling report to identify performance bottlenecks and opportunities for optimization.</p>
</li>
</ol>
<h3 id="heading-debugging-with-xdebug">Debugging with Xdebug</h3>
<ol>
<li><p>Install the Xdebug extension on your server.</p>
</li>
<li><p>Configure Xdebug by updating your <code>php.ini</code> file with the necessary settings.</p>
</li>
<li><p>Use a PHP IDE, such as PHPStorm or Visual Studio Code, to enable Xdebug integration and start debugging your application.</p>
</li>
<li><p>Step through your code, inspect variables, and use Xdebug's profiling capabilities to identify performance issues.</p>
</li>
</ol>
<h2 id="heading-best-practices-for-php-performance-optimization">Best Practices for PHP Performance Optimization</h2>
<p>Alongside using performance monitoring tools, there are several best practices you can follow to improve and maintain the performance of your PHP application:</p>
<ol>
<li><p><strong>Optimize Database Queries</strong>: Ensure that your SQL queries are optimized, avoid N+1 query problems, and consider caching frequently accessed data.</p>
</li>
<li><p><strong>Utilize Caching</strong>: Implement caching mechanisms, such as Memcached or Redis, to reduce the load on your database and server resources.</p>
</li>
<li><p><strong>Optimize Code</strong>: Identify and address performance bottlenecks in your PHP code, such as inefficient algorithms, unnecessary function calls, or resource-intensive operations.</p>
</li>
<li><p><strong>Leverage Asynchronous Processing</strong>: Use asynchronous processing, such as queues or background workers, to offload long-running or resource-intensive tasks.</p>
</li>
<li><p><strong>Monitor and Troubleshoot</strong>: Continuously monitor your application's performance, analyze the data provided by your monitoring tools, and quickly address any emerging issues.</p>
</li>
</ol>
<h2 id="heading-conclusion-and-further-resources">Conclusion and Further Resources</h2>
<p>In this blog post, we've explored the essentials of PHP performance monitoring, including key performance metrics, popular tools and techniques, and best practices for optimization. By implementing a comprehensive performance monitoring strategy, you can ensure your PHP applications are efficient, reliable, and provide a seamless user experience.</p>
<p>For those interested in diving deeper into advanced PHP performance monitoring strategies, I recommend exploring resources such as the New Relic documentation, the Blackfire blog, and the Xdebug user guide. Additionally, staying up-to-date with the latest PHP performance-related articles and tutorials can help you continuously improve the performance of your applications.</p>
]]></content:encoded></item><item><title><![CDATA[Distributed Caching Architectures in Laravel: A Beginner's Guide]]></title><description><![CDATA[Distributed Caching Architectures in Laravel
Introduction
Imagine you're preparing breakfast every morning. Instead of taking out all the ingredients from different cabinets each time, you keep frequently used items like coffee, sugar, and bread on t...]]></description><link>https://notes.sohag.pro/distributed-caching-architectures-in-laravel-a-beginners-guide</link><guid isPermaLink="true">https://notes.sohag.pro/distributed-caching-architectures-in-laravel-a-beginners-guide</guid><category><![CDATA[caching]]></category><category><![CDATA[PHP]]></category><category><![CDATA[Laravel]]></category><dc:creator><![CDATA[Sohag Hasan]]></dc:creator><pubDate>Tue, 05 Nov 2024 22:19:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1730845111358/f94b37c1-f0d1-484c-aace-1f6ee41c656a.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-distributed-caching-architectures-in-laravel">Distributed Caching Architectures in Laravel</h1>
<h2 id="heading-introduction">Introduction</h2>
<p>Imagine you're preparing breakfast every morning. Instead of taking out all the ingredients from different cabinets each time, you keep frequently used items like coffee, sugar, and bread on the counter for quick access. This is exactly how caching works in web applications – keeping frequently accessed data readily available to serve requests faster.</p>
<p>In Laravel applications, caching becomes crucial as your application grows and handles more users. Just as a busy café can't rely on a single coffee machine during rush hour, your application can't depend on a single cache store when scaling up. This is where distributed caching comes into play.</p>
<h2 id="heading-understanding-basic-caching-in-laravel">Understanding Basic Caching in Laravel</h2>
<p>Before diving into distributed patterns, let's understand how basic caching works in Laravel:</p>
<pre><code class="lang-php"><span class="hljs-comment">// Storing data in cache</span>
Cache::put(<span class="hljs-string">'user_profile'</span>, $userProfile, now()-&gt;addHours(<span class="hljs-number">24</span>));

<span class="hljs-comment">// Retrieving data from cache</span>
$userProfile = Cache::get(<span class="hljs-string">'user_profile'</span>);

<span class="hljs-comment">// Store if not exists</span>
$value = Cache::remember(<span class="hljs-string">'users'</span>, <span class="hljs-number">3600</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> DB::table(<span class="hljs-string">'users'</span>)-&gt;get();
});
</code></pre>
<h2 id="heading-distributed-caching-patterns">Distributed Caching Patterns</h2>
<h3 id="heading-1-replication-pattern">1. Replication Pattern</h3>
<p>Think of replication like having multiple copies of your favorite recipe book in different locations. If one gets damaged, you can still access the recipes from another copy.</p>
<h4 id="heading-implementation-example">Implementation Example:</h4>
<pre><code class="lang-php"><span class="hljs-comment">// config/cache.php</span>
<span class="hljs-string">'stores'</span> =&gt; [
    <span class="hljs-string">'distributed'</span> =&gt; [
        <span class="hljs-string">'driver'</span> =&gt; <span class="hljs-string">'redis'</span>,
        <span class="hljs-string">'connection'</span> =&gt; <span class="hljs-string">'cache'</span>,
        <span class="hljs-string">'replicas'</span> =&gt; [
            [<span class="hljs-string">'host'</span> =&gt; <span class="hljs-string">'redis-1.example.com'</span>, <span class="hljs-string">'port'</span> =&gt; <span class="hljs-number">6379</span>],
            [<span class="hljs-string">'host'</span> =&gt; <span class="hljs-string">'redis-2.example.com'</span>, <span class="hljs-string">'port'</span> =&gt; <span class="hljs-number">6379</span>],
        ],
    ],
],
</code></pre>
<h4 id="heading-usage">Usage:</h4>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserController</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Controller</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">show</span>(<span class="hljs-params">$id</span>)
    </span>{
        <span class="hljs-keyword">return</span> Cache::store(<span class="hljs-string">'distributed'</span>)-&gt;remember(
            <span class="hljs-string">"user.<span class="hljs-subst">{$id}</span>"</span>,
            <span class="hljs-number">3600</span>,
            <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) <span class="hljs-title">use</span> (<span class="hljs-params">$id</span>) </span>{
                <span class="hljs-keyword">return</span> User::find($id);
            }
        );
    }
}
</code></pre>
<h3 id="heading-2-sharding-pattern">2. Sharding Pattern</h3>
<p>Sharding is like organizing your wardrobe by categories – putting shirts in one drawer, pants in another. Each cache server handles specific types of data.</p>
<h4 id="heading-implementation">Implementation:</h4>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ShardedCache</span>
</span>{
    <span class="hljs-keyword">protected</span> $shards = [
        <span class="hljs-string">'users'</span> =&gt; <span class="hljs-string">'redis-1'</span>,
        <span class="hljs-string">'products'</span> =&gt; <span class="hljs-string">'redis-2'</span>,
        <span class="hljs-string">'orders'</span> =&gt; <span class="hljs-string">'redis-3'</span>
    ];

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">get</span>(<span class="hljs-params">$key</span>)
    </span>{
        $shard = <span class="hljs-keyword">$this</span>-&gt;determineShardByKey($key);
        <span class="hljs-keyword">return</span> Cache::store($shard)-&gt;get($key);
    }

    <span class="hljs-keyword">protected</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">determineShardByKey</span>(<span class="hljs-params">$key</span>)
    </span>{
        $prefix = explode(<span class="hljs-string">'.'</span>, $key)[<span class="hljs-number">0</span>];
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;shards[$prefix] ?? <span class="hljs-string">'default'</span>;
    }
}
</code></pre>
<h3 id="heading-3-partitioning-pattern">3. Partitioning Pattern</h3>
<p>Partitioning distributes data across servers based on a consistent hashing algorithm, like dividing students into different classrooms based on their last names.</p>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PartitionedCache</span>
</span>{
    <span class="hljs-keyword">protected</span> $nodes = [
        <span class="hljs-string">'cache-1'</span> =&gt; [<span class="hljs-string">'start'</span> =&gt; <span class="hljs-number">0</span>, <span class="hljs-string">'end'</span> =&gt; <span class="hljs-number">1000</span>],
        <span class="hljs-string">'cache-2'</span> =&gt; [<span class="hljs-string">'start'</span> =&gt; <span class="hljs-number">1001</span>, <span class="hljs-string">'end'</span> =&gt; <span class="hljs-number">2000</span>],
        <span class="hljs-string">'cache-3'</span> =&gt; [<span class="hljs-string">'start'</span> =&gt; <span class="hljs-number">2001</span>, <span class="hljs-string">'end'</span> =&gt; <span class="hljs-number">3000</span>],
    ];

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">set</span>(<span class="hljs-params">$key, $value, $ttl = <span class="hljs-number">3600</span></span>)
    </span>{
        $node = <span class="hljs-keyword">$this</span>-&gt;getNodeForKey($key);
        <span class="hljs-keyword">return</span> Cache::store($node)-&gt;put($key, $value, $ttl);
    }

    <span class="hljs-keyword">protected</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getNodeForKey</span>(<span class="hljs-params">$key</span>)
    </span>{
        $hash = crc32($key) % <span class="hljs-number">3000</span>;

        <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">$this</span>-&gt;nodes <span class="hljs-keyword">as</span> $node =&gt; $range) {
            <span class="hljs-keyword">if</span> ($hash &gt;= $range[<span class="hljs-string">'start'</span>] &amp;&amp; $hash &lt;= $range[<span class="hljs-string">'end'</span>]) {
                <span class="hljs-keyword">return</span> $node;
            }
        }
    }
}
</code></pre>
<h2 id="heading-best-practices">Best Practices</h2>
<ol>
<li><strong>Cache Invalidation Strategy</strong></li>
</ol>
<pre><code class="lang-php"><span class="hljs-comment">// Use tags for easier cache management</span>
Cache::tags([<span class="hljs-string">'users'</span>, <span class="hljs-string">"user.<span class="hljs-subst">{$id}</span>"</span>])-&gt;put(<span class="hljs-string">"user.<span class="hljs-subst">{$id}</span>"</span>, $userData, <span class="hljs-number">3600</span>);

<span class="hljs-comment">// Invalidate all user-related caches</span>
Cache::tags([<span class="hljs-string">'users'</span>])-&gt;flush();
</code></pre>
<ol start="2">
<li><strong>Handle Cache Failures Gracefully</strong></li>
</ol>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getData</span>(<span class="hljs-params">$key</span>)
</span>{
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">return</span> Cache::get($key, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;fetchFromDatabase();
        });
    } <span class="hljs-keyword">catch</span> (<span class="hljs-built_in">Exception</span> $e) {
        Log::error(<span class="hljs-string">"Cache error: "</span> . $e-&gt;getMessage());
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;fetchFromDatabase();
    }
}
</code></pre>
<ol start="3">
<li><strong>Implement Cache Warming</strong></li>
</ol>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WarmCache</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handle</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-comment">// Pre-cache frequently accessed data</span>
        $popularProducts = Product::popular()-&gt;get();
        Cache::tags([<span class="hljs-string">'products'</span>])-&gt;put(<span class="hljs-string">'popular_products'</span>, $popularProducts, now()-&gt;addDay());
    }
}
</code></pre>
<h2 id="heading-monitoring-and-debugging">Monitoring and Debugging</h2>
<pre><code class="lang-php"><span class="hljs-comment">// Add cache hit/miss monitoring</span>
Cache::extend(<span class="hljs-string">'monitored'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">$app</span>) </span>{
    <span class="hljs-keyword">return</span> Cache::repository(<span class="hljs-keyword">new</span> MonitoredStore(
        <span class="hljs-keyword">new</span> RedisStore($app[<span class="hljs-string">'redis'</span>]),
        $app[<span class="hljs-string">'events'</span>]
    ));
});

<span class="hljs-comment">// Listen for cache events</span>
Event::listen(<span class="hljs-string">'cache.hit'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">$key</span>) </span>{
    Log::info(<span class="hljs-string">"Cache hit for key: <span class="hljs-subst">{$key}</span>"</span>);
});
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Distributed caching is essential for scaling Laravel applications effectively. By understanding and implementing these patterns correctly, you can significantly improve your application's performance and reliability. Remember:</p>
<ul>
<li><p>Use replication for high availability</p>
</li>
<li><p>Implement sharding for better resource utilization</p>
</li>
<li><p>Consider partitioning for balanced data distribution</p>
</li>
<li><p>Always implement proper monitoring and fallback mechanisms</p>
</li>
</ul>
<h2 id="heading-further-learning">Further Learning</h2>
<p>To deepen your understanding of distributed caching, explore these topics:</p>
<ol>
<li><p>Redis Cluster Configuration and Management</p>
</li>
<li><p>Cache Coherency Protocols</p>
</li>
<li><p>Event-Driven Cache Invalidation</p>
</li>
<li><p>Cache-Aside vs. Write-Through Patterns</p>
</li>
<li><p>Laravel Horizon for Redis Queue Management</p>
</li>
</ol>
<p>Remember that caching is an optimization technique that requires careful consideration of your specific use case. Start with simple implementations and gradually move to more complex patterns as your application's needs grow.</p>
]]></content:encoded></item><item><title><![CDATA[Understanding PHP Caching: A Comprehensive Guide for Beginners]]></title><description><![CDATA[Caching in PHP and Laravel
Introduction
Imagine walking to your kitchen every time you need a glass of water versus keeping a water bottle at your desk. That's essentially what caching is in programming - keeping frequently used data closer for quick...]]></description><link>https://notes.sohag.pro/understanding-php-caching-a-comprehensive-guide-for-beginners</link><guid isPermaLink="true">https://notes.sohag.pro/understanding-php-caching-a-comprehensive-guide-for-beginners</guid><category><![CDATA[caching]]></category><category><![CDATA[PHP]]></category><dc:creator><![CDATA[Sohag Hasan]]></dc:creator><pubDate>Tue, 05 Nov 2024 22:11:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1730844624140/d62e0cba-c968-4279-8d81-57d7aecad5f6.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-caching-in-php-and-laravel">Caching in PHP and Laravel</h1>
<h2 id="heading-introduction">Introduction</h2>
<p>Imagine walking to your kitchen every time you need a glass of water versus keeping a water bottle at your desk. That's essentially what caching is in programming - keeping frequently used data closer for quick access. In this guide, we'll explore caching in PHP, from basic concepts to advanced implementation with Laravel, making it relatable and practical for everyday development.</p>
<h2 id="heading-why-you-should-care">Why You Should Care</h2>
<ul>
<li><p><strong>Speed</strong>: Your applications can run up to 1000% faster with proper caching</p>
</li>
<li><p><strong>Cost Savings</strong>: Reduced server load means lower hosting costs</p>
</li>
<li><p><strong>User Experience</strong>: Faster response times = happier users</p>
</li>
<li><p><strong>Scalability</strong>: Handle more users without proportionally increasing resources</p>
</li>
</ul>
<p>Think about it: Netflix doesn't re-encode a movie every time someone wants to watch it. They cache the encoded versions. Similarly, your PHP application shouldn't recalculate or refetch the same data repeatedly.</p>
<h2 id="heading-basic-caching-concepts">Basic Caching Concepts</h2>
<h3 id="heading-1-application-level-caching">1. Application-Level Caching</h3>
<p>Think of this as your personal notepad where you jot down important information for quick reference.</p>
<pre><code class="lang-php"><span class="hljs-comment">// Without caching</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">calculateComplexValue</span>(<span class="hljs-params">$input</span>) </span>{
    <span class="hljs-comment">// Complex calculation that takes time</span>
    sleep(<span class="hljs-number">2</span>); <span class="hljs-comment">// Simulating complex calculation</span>
    <span class="hljs-keyword">return</span> $input * <span class="hljs-number">2</span>;
}

<span class="hljs-comment">// With caching</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">calculateComplexValueCached</span>(<span class="hljs-params">$input</span>) </span>{
    <span class="hljs-built_in">static</span> $cache = [];

    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">isset</span>($cache[$input])) {
        <span class="hljs-keyword">return</span> $cache[$input]; <span class="hljs-comment">// Return cached result</span>
    }

    <span class="hljs-comment">// Calculate and cache result</span>
    $cache[$input] = $input * <span class="hljs-number">2</span>;
    <span class="hljs-keyword">return</span> $cache[$input];
}
</code></pre>
<p>Real-life example: Like keeping your frequently used cooking ingredients on the counter instead of the storage room.</p>
<h3 id="heading-2-database-query-caching-with-laravel">2. Database Query Caching with Laravel</h3>
<p>Similar to how a barista remembers regular customers' orders, Laravel can remember database query results.</p>
<pre><code class="lang-php"><span class="hljs-comment">// Without caching</span>
$users = DB::table(<span class="hljs-string">'users'</span>)
    -&gt;where(<span class="hljs-string">'active'</span>, <span class="hljs-number">1</span>)
    -&gt;get();

<span class="hljs-comment">// With caching</span>
$users = Cache::remember(<span class="hljs-string">'active_users'</span>, <span class="hljs-number">3600</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> DB::table(<span class="hljs-string">'users'</span>)
        -&gt;where(<span class="hljs-string">'active'</span>, <span class="hljs-number">1</span>)
        -&gt;get();
});
</code></pre>
<p>Real-life example: A restaurant keeping its most-ordered dishes pre-prepared during rush hour.</p>
<h3 id="heading-3-view-caching">3. View Caching</h3>
<p>Think of this as taking a snapshot of your finished artwork instead of redrawing it every time.</p>
<pre><code class="lang-php"><span class="hljs-comment">// In your blade template</span>
@cache(<span class="hljs-string">'unique_key'</span>, <span class="hljs-number">3600</span>)
    @<span class="hljs-keyword">foreach</span>($products <span class="hljs-keyword">as</span> $product)
        &lt;div <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">product</span>-<span class="hljs-title">card</span>"&gt;
            </span>{{ $product-&gt;name }}
        &lt;/div&gt;
    @<span class="hljs-keyword">endforeach</span>
@endcache
</code></pre>
<h2 id="heading-advanced-caching-techniques">Advanced Caching Techniques</h2>
<h3 id="heading-1-redis-implementation">1. Redis Implementation</h3>
<p>Redis is like having a super-fast assistant who remembers everything.</p>
<pre><code class="lang-php"><span class="hljs-comment">// Configure Redis in .env</span>
REDIS_HOST=<span class="hljs-number">127.0</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span>
REDIS_PORT=<span class="hljs-number">6379</span>

<span class="hljs-comment">// Using Redis in Laravel</span>
<span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Support</span>\<span class="hljs-title">Facades</span>\<span class="hljs-title">Redis</span>;

Redis::set(<span class="hljs-string">'user:1'</span>, json_encode($userData));
$userData = json_decode(Redis::get(<span class="hljs-string">'user:1'</span>));
</code></pre>
<h3 id="heading-2-custom-cache-driver">2. Custom Cache Driver</h3>
<p>Creating your own cache driver is like building a custom storage solution for specific needs.</p>
<pre><code class="lang-php"><span class="hljs-keyword">namespace</span> <span class="hljs-title">App</span>\<span class="hljs-title">Cache</span>;

<span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Contracts</span>\<span class="hljs-title">Cache</span>\<span class="hljs-title">Store</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CustomCache</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Store</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">get</span>(<span class="hljs-params">$key</span>)
    </span>{
        <span class="hljs-comment">// Custom implementation</span>
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">put</span>(<span class="hljs-params">$key, $value, $seconds</span>)
    </span>{
        <span class="hljs-comment">// Custom implementation</span>
    }

    <span class="hljs-comment">// Other required methods...</span>
}
</code></pre>
<h3 id="heading-3-cache-tags">3. Cache Tags</h3>
<p>Like organizing your files with labels for easy access.</p>
<pre><code class="lang-php"><span class="hljs-comment">// Storing with tags</span>
Cache::tags([<span class="hljs-string">'users'</span>, <span class="hljs-string">'profiles'</span>])-&gt;put(<span class="hljs-string">'user:1'</span>, $userData, <span class="hljs-number">3600</span>);

<span class="hljs-comment">// Retrieving tagged cache</span>
$userData = Cache::tags([<span class="hljs-string">'users'</span>])-&gt;get(<span class="hljs-string">'user:1'</span>);

<span class="hljs-comment">// Flush specific tags</span>
Cache::tags([<span class="hljs-string">'users'</span>])-&gt;flush();
</code></pre>
<h2 id="heading-best-practices">Best Practices</h2>
<ol>
<li><p><strong>Cache Invalidation Strategy</strong></p>
<ul>
<li><p>Set appropriate TTL (Time To Live)</p>
</li>
<li><p>Use cache tags for grouped invalidation</p>
</li>
<li><p>Implement versioning for cache keys</p>
</li>
</ul>
</li>
</ol>
<pre><code class="lang-php"><span class="hljs-comment">// Using cache versioning</span>
$cacheKey = <span class="hljs-string">"users_list_v"</span> . config(<span class="hljs-string">'cache.version'</span>);
</code></pre>
<ol start="2">
<li><p><strong>Security Considerations</strong></p>
<ul>
<li><p>Never cache sensitive data</p>
</li>
<li><p>Implement cache key prefixes</p>
</li>
<li><p>Use encryption when necessary</p>
</li>
</ul>
</li>
</ol>
<pre><code class="lang-php"><span class="hljs-comment">// Secure caching</span>
Cache::tags([<span class="hljs-string">'secure'</span>])-&gt;put(
    <span class="hljs-string">'user_data_'</span> . hash(<span class="hljs-string">'sha256'</span>, $userId),
    encrypt($userData),
    <span class="hljs-number">3600</span>
);
</code></pre>
<ol start="3">
<li><p><strong>Performance Monitoring</strong></p>
<ul>
<li><p>Monitor cache hit/miss ratios</p>
</li>
<li><p>Implement cache warming strategies</p>
</li>
<li><p>Use cache race condition prevention</p>
</li>
</ul>
</li>
</ol>
<pre><code class="lang-php"><span class="hljs-comment">// Atomic cache operations</span>
Cache::lock(<span class="hljs-string">'processing_data'</span>)-&gt;get(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// Process and cache data</span>
});
</code></pre>
<h2 id="heading-topics-to-explore-further">Topics to Explore Further</h2>
<ol>
<li><p><strong>Cache Backends</strong></p>
<ul>
<li><p>Memcached vs Redis</p>
</li>
<li><p>File-based caching</p>
</li>
<li><p>Database caching</p>
</li>
</ul>
</li>
<li><p><strong>Advanced Laravel Caching</strong></p>
<ul>
<li><p>Queue workers with cache</p>
</li>
<li><p>Broadcasting with cache</p>
</li>
<li><p>Rate limiting using cache</p>
</li>
</ul>
</li>
<li><p><strong>Distributed Caching</strong></p>
<ul>
<li><p>Cache synchronization</p>
</li>
<li><p>Cache replication</p>
</li>
<li><p>Cache clustering</p>
</li>
</ul>
</li>
</ol>
<h2 id="heading-common-caching-patterns-and-real-life-analogies">Common Caching Patterns and Real-Life Analogies</h2>
<ol>
<li><p><strong>Cache-Aside (Lazy Loading)</strong></p>
<ul>
<li>Like checking your pocket before going to the ATM</li>
</ul>
</li>
</ol>
<pre><code class="lang-php">    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getData</span>(<span class="hljs-params">$key</span>) </span>{
        <span class="hljs-keyword">if</span> (!Cache::has($key)) {
            Cache::put($key, fetchFromDatabase(), <span class="hljs-number">3600</span>);
        }
        <span class="hljs-keyword">return</span> Cache::get($key);
    }
</code></pre>
<ol start="2">
<li><p><strong>Write-Through</strong></p>
<ul>
<li>Like updating both your digital and paper calendar simultaneously</li>
</ul>
</li>
</ol>
<pre><code class="lang-php">    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">saveData</span>(<span class="hljs-params">$key, $value</span>) </span>{
        Database::save($value);
        Cache::put($key, $value, <span class="hljs-number">3600</span>);
    }
</code></pre>
<ol start="3">
<li><p><strong>Write-Behind</strong></p>
<ul>
<li>Like collecting dishes in a bin and washing them all at once</li>
</ul>
</li>
</ol>
<pre><code class="lang-php">    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">saveData</span>(<span class="hljs-params">$key, $value</span>) </span>{
        Cache::put($key, $value, <span class="hljs-number">3600</span>);
        dispatch(<span class="hljs-keyword">new</span> UpdateDatabaseJob($key, $value));
    }
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Caching is not just a performance optimization technique; it's a fundamental concept that can make or break your application's success. Like a well-organized kitchen where everything has its place, proper caching ensures your PHP application runs smoothly and efficiently. Start with basic caching techniques and gradually move to more advanced patterns as your application grows.</p>
<p>Remember: The best caching strategy is the one that fits your specific needs. Don't overcomplicate it initially - start simple and optimize based on real usage patterns.</p>
<hr />
<p><em>Further Reading:</em></p>
<ul>
<li><p>Laravel Official Documentation on Caching</p>
</li>
<li><p>Redis Documentation</p>
</li>
<li><p>PHP OpCache Configuration</p>
</li>
<li><p>Memcached vs Redis Comparison</p>
</li>
<li><p>Distributed Caching Architectures</p>
</li>
</ul>
]]></content:encoded></item></channel></rss>