<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Bala Audu Musa</title>
    <description>The latest articles on DEV Community by Bala Audu Musa (@bala_audu_musa).</description>
    <link>https://dev.to/bala_audu_musa</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2823629%2F642051bc-e206-4983-96a7-4d214baeb969.jpg</url>
      <title>DEV Community: Bala Audu Musa</title>
      <link>https://dev.to/bala_audu_musa</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bala_audu_musa"/>
    <language>en</language>
    <item>
      <title>Weather Report Automation</title>
      <dc:creator>Bala Audu Musa</dc:creator>
      <pubDate>Mon, 05 Jan 2026 01:53:52 +0000</pubDate>
      <link>https://dev.to/bala_audu_musa/weather-report-automation-4h4a</link>
      <guid>https://dev.to/bala_audu_musa/weather-report-automation-4h4a</guid>
      <description>&lt;p&gt;&lt;strong&gt;Aim:&lt;/strong&gt; &lt;br&gt;
To build an AI agent that we can speak to and it tells us the weather condition of any place we want.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flqdmpnrfm2expkihs2ra.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flqdmpnrfm2expkihs2ra.png" alt=" " width="800" height="439"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tools&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vapi&lt;/li&gt;
&lt;li&gt;Large Language Model (LLM) like OpenAI, Gemini AI etc.&lt;/li&gt;
&lt;li&gt;n8n&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Visit &lt;a href="https://n8n.io/workflows/" rel="noopener noreferrer"&gt;https://n8n.io/workflows/&lt;/a&gt; to &lt;strong&gt;sign in&lt;/strong&gt; to &lt;strong&gt;n8n&lt;/strong&gt; if you already have an account. Or &lt;strong&gt;Get Started&lt;/strong&gt; to create one.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvp4yr9jpsm0r6qaqx8oe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvp4yr9jpsm0r6qaqx8oe.png" alt=" " width="800" height="276"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since I had created account already, I will be signing in. Thenafter, I click on &lt;strong&gt;Open Instance&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F721tkx837qb6f3syusxo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F721tkx837qb6f3syusxo.png" alt=" " width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on &lt;strong&gt;Workflows&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6ng63d1zn9c74zh1khrj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6ng63d1zn9c74zh1khrj.png" alt=" " width="800" height="254"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the &lt;strong&gt;Large Plus (+)&lt;/strong&gt; sign above where is written &lt;strong&gt;Add first step...&lt;/strong&gt; or &lt;strong&gt;start from a template&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frnq0ili54wis70w0x7ti.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frnq0ili54wis70w0x7ti.png" alt=" " width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Search for &lt;strong&gt;Webhook&lt;/strong&gt; and select in the dropdown&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvrjjevv691sloxvh72jk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvrjjevv691sloxvh72jk.png" alt=" " width="462" height="697"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Search for &lt;strong&gt;AI agent&lt;/strong&gt; and click it in the drop down.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh2pvt9sbii7kq7r8tsa5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh2pvt9sbii7kq7r8tsa5.png" alt=" " width="487" height="711"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the bar where &lt;strong&gt;GET&lt;/strong&gt; is and select &lt;strong&gt;POST&lt;/strong&gt; in the drop-down. Leave every other thing in &lt;strong&gt;default&lt;/strong&gt; and click on &lt;strong&gt;(x)&lt;/strong&gt; to close the page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzhp7dza4m5xko8lamxzu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzhp7dza4m5xko8lamxzu.png" alt=" " width="778" height="752"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the &lt;strong&gt;plus (+)&lt;/strong&gt; to the right of &lt;strong&gt;Webhook&lt;/strong&gt; and search &lt;strong&gt;AI agent&lt;/strong&gt; in the popped-out dialog box and select it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdui9ttvabjm84ycc0f3c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdui9ttvabjm84ycc0f3c.png" alt=" " width="800" height="340"&gt;&lt;/a&gt;&lt;br&gt;
Close the page that opened.&lt;/p&gt;

&lt;p&gt;Let's now add a &lt;strong&gt;weather_tool&lt;/strong&gt;&lt;br&gt;
Click on the &lt;strong&gt;plus (+)&lt;/strong&gt; under tool. Search for &lt;strong&gt;Weather&lt;/strong&gt; in the bar and Select the &lt;strong&gt;OpenWeatherMap tool&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you have not created credentials for &lt;strong&gt;OpenWeatherMap&lt;/strong&gt; do it. In the &lt;strong&gt;City bar&lt;/strong&gt; click on &lt;strong&gt;the stars **to automatically get that decided by **AI&lt;/strong&gt;. Close the page after that.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5cf36ppxix4e9w3cro4b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5cf36ppxix4e9w3cro4b.png" alt=" " width="796" height="718"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lets now add chat model&lt;br&gt;
Click on the &lt;strong&gt;plus (+)&lt;/strong&gt; below chat model. Under the &lt;strong&gt;language models&lt;/strong&gt; dialog box search for &lt;strong&gt;Gemini&lt;/strong&gt; or &lt;strong&gt;OpenAI&lt;/strong&gt; etc. In this case I am searching for Gemini because I had exhausted my credit in OpenAI.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbkc23eg4t03bhdtpnf7a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbkc23eg4t03bhdtpnf7a.png" alt=" " width="800" height="358"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You need to create credential and generate &lt;strong&gt;an API&lt;/strong&gt; if you have not done so. Select the &lt;strong&gt;flash&lt;/strong&gt; option of Gemini.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg8it4sll1sg8zk19ldrf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg8it4sll1sg8zk19ldrf.png" alt=" " width="792" height="617"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Close the window.&lt;/p&gt;

&lt;p&gt;Let's now setup &lt;strong&gt;VAPI&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Create an account&lt;/strong&gt; or &lt;strong&gt;sign in&lt;/strong&gt;. I am using my &lt;strong&gt;Github account&lt;/strong&gt; to sign in in this case.&lt;/p&gt;

&lt;p&gt;Click on &lt;strong&gt;Assistants&lt;/strong&gt; and then click on &lt;strong&gt;Create Assistant&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffroazip5q133wgoq3bht.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffroazip5q133wgoq3bht.png" alt=" " width="800" height="331"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Give the your &lt;strong&gt;Assistant&lt;/strong&gt; a name. Lets call it &lt;strong&gt;Weather Agent.&lt;/strong&gt;&lt;br&gt;
Then click on &lt;strong&gt;Create Assistant&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp7gsn7xwyvh584eizpmo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp7gsn7xwyvh584eizpmo.png" alt=" " width="747" height="862"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Under &lt;strong&gt;model&lt;/strong&gt;; type in the &lt;strong&gt;First Message&lt;/strong&gt; and the &lt;strong&gt;System Prompt&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frsolmrrlrp16a1vc1o0s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frsolmrrlrp16a1vc1o0s.png" alt=" " width="800" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let's now create the Weather_tool.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Scroll down to &lt;strong&gt;Tools&lt;/strong&gt;. Click on the &lt;strong&gt;Tools bar&lt;/strong&gt; and click on &lt;strong&gt;Create New Tool&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9yujqipm90wjv0qgdfl0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9yujqipm90wjv0qgdfl0.png" alt=" " width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on &lt;strong&gt;Create Tool&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F05b5ks3gh7qp90tcs5kz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F05b5ks3gh7qp90tcs5kz.png" alt=" " width="800" height="130"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on &lt;strong&gt;Custom Tool&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5cjlgdtkjnvvaa007v9o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5cjlgdtkjnvvaa007v9o.png" alt=" " width="322" height="516"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Rename the tool as &lt;strong&gt;Weather1_tool&lt;/strong&gt;. And Give a description below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F09jlx85dihh202iyw0y0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F09jlx85dihh202iyw0y0.png" alt=" " width="800" height="327"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Scroll down to Parameters and click on &lt;strong&gt;+ Add Property&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1afqnne1yx62xnvd9oqz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1afqnne1yx62xnvd9oqz.png" alt=" " width="800" height="269"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Give the Parameter name; &lt;strong&gt;Place&lt;/strong&gt; and &lt;strong&gt;write a description&lt;/strong&gt; and click on &lt;strong&gt;Apply&lt;/strong&gt;. Don't click  on &lt;strong&gt;Required&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdum8t9xh8kc2wyziw7lp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdum8t9xh8kc2wyziw7lp.png" alt=" " width="800" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Scroll to &lt;strong&gt;Server Settings&lt;/strong&gt;&lt;br&gt;
For the &lt;strong&gt;Server URL&lt;/strong&gt;, we need to go back to &lt;strong&gt;n8n&lt;/strong&gt;, &lt;strong&gt;double click&lt;/strong&gt; on &lt;strong&gt;Webhook&lt;/strong&gt; and copy the &lt;strong&gt;POST URL&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F40v4529p4dk5a2zq1u6s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F40v4529p4dk5a2zq1u6s.png" alt=" " width="780" height="301"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go back to &lt;strong&gt;Vapi&lt;/strong&gt; and paste the URL in the &lt;strong&gt;Server URL bar&lt;/strong&gt;. Then click on &lt;strong&gt;Save&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffj4jlehbymtky3d5q1w7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffj4jlehbymtky3d5q1w7.png" alt=" " width="800" height="279"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We just finished setting up our &lt;strong&gt;Weather_tool&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Click on Assistants and then click on Tools.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffwz3tji0c7dydto9meb0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffwz3tji0c7dydto9meb0.png" alt=" " width="800" height="298"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on &lt;strong&gt;Select Tool bar&lt;/strong&gt; and click to Select the &lt;strong&gt;weather_tool&lt;/strong&gt; we just created.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0q2mfn10xi8knni4wbjo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0q2mfn10xi8knni4wbjo.png" alt=" " width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on &lt;strong&gt;Publish&lt;/strong&gt; at the top right-hand corner of the page.&lt;/p&gt;

&lt;p&gt;Click on Configure Structured Output. Select the first one; &lt;strong&gt;Call Summary&lt;/strong&gt; and click on &lt;strong&gt;Next&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr8krkndkpl9yu0titslq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr8krkndkpl9yu0titslq.png" alt=" " width="800" height="321"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on &lt;strong&gt;Publish&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Back to n8n. Click on &lt;strong&gt;Listen for test event&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu51u5hkvj4qvgb8aclub.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu51u5hkvj4qvgb8aclub.png" alt=" " width="800" height="291"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As it starts listening... Go back to Vapi and click on &lt;strong&gt;Talk to Assistant&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdygg8mid4fgojwuwt1q4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdygg8mid4fgojwuwt1q4.png" alt=" " width="800" height="196"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Weather Assistant will call to ask you where you want to get its weather. On telling it. It will say he is not able to get it. That is true. We now need to configure the part it actually gives a good reply.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhlzsf027eqw1tgzgv9w2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhlzsf027eqw1tgzgv9w2.png" alt=" " width="580" height="685"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;End the call. Back to n8n. You should see the output dialog box has been populated with data on the call you just made.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdu3vdmtu7x7x43tc5hc1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdu3vdmtu7x7x43tc5hc1.png" alt=" " width="657" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Double click on your AI Agent in n8n. And under &lt;strong&gt;Source for Prompt (User Message)&lt;/strong&gt; select &lt;strong&gt;Define below&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxy0whzbp8br2a13wljvs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxy0whzbp8br2a13wljvs.png" alt=" " width="680" height="460"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Type in the Prompt box and move in codes from the left panel to represent key indices. Make sure you select &lt;strong&gt;Expression&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbiyed2p5ry1xgg68kway.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbiyed2p5ry1xgg68kway.png" alt=" " width="800" height="121"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lets now add a Response to Webhook&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftv3hrrvut7h0t7vm2pkm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftv3hrrvut7h0t7vm2pkm.png" alt=" " width="800" height="288"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Double click on &lt;strong&gt;Webhook&lt;/strong&gt; and click on &lt;strong&gt;Using&lt;/strong&gt; &lt;strong&gt;'Respond to Webhook Nodes'&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5gcgax9xi48x9cr4bc6x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5gcgax9xi48x9cr4bc6x.png" alt=" " width="668" height="320"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on &lt;strong&gt;Execute workflows&lt;/strong&gt; in n8n and go to Vapi to &lt;strong&gt;Talk to Assistant&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa4sx1ifut8xulgf5yp2c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa4sx1ifut8xulgf5yp2c.png" alt=" " width="598" height="713"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will notice it still could not give us intend answer. That is natural. Let's tweak it a bit further.&lt;/p&gt;

&lt;p&gt;Double click on &lt;strong&gt;Respond to Webhook&lt;/strong&gt;. You should see the Output format. Now that format can't be sent to Vapi. Hence, why Vapi didnt response to us.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmdz0p8umhduk9ify269r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmdz0p8umhduk9ify269r.png" alt=" " width="765" height="337"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Message sent to Vapi has to be in a particular format. Now let's open Vapi Documentation.&lt;/p&gt;

&lt;p&gt;Click on Custom Tools. Scroll to &lt;strong&gt;Server Response Format: Providing Results and Context&lt;/strong&gt; and copy the JSON.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp0s7jwfyvkp0z5j2vlpn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp0s7jwfyvkp0z5j2vlpn.png" alt=" " width="800" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Back to n8n. Double click on &lt;strong&gt;Respond to Webhook&lt;/strong&gt;. Click on First incoming message bar and select JSON in the drop-down.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1yv53josgii3z2bw3fx9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1yv53josgii3z2bw3fx9.png" alt=" " width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Paste the JSON you have copied into the &lt;strong&gt;Respond body&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frohavjpqjjghal70dwwb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frohavjpqjjghal70dwwb.png" alt=" " width="626" height="442"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Replace CallID X and &lt;strong&gt;Result Y&lt;/strong&gt; with their equivalent from the left pane.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F94gsopj8xab0y1qztey3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F94gsopj8xab0y1qztey3.png" alt=" " width="800" height="184"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7gbm8o3x8uhamp0d9huc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7gbm8o3x8uhamp0d9huc.png" alt=" " width="800" height="330"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's test again.&lt;br&gt;
Execute workflows. Then click on Talk to Assistant&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flqa3q7bgsrwj0ril9vlx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flqa3q7bgsrwj0ril9vlx.png" alt=" " width="616" height="866"&gt;&lt;/a&gt;&lt;br&gt;
This is what success looks like. Alhamdulillah.&lt;/p&gt;

&lt;p&gt;.&lt;/p&gt;

</description>
      <category>vapi</category>
      <category>webhook</category>
      <category>automation</category>
      <category>agents</category>
    </item>
    <item>
      <title>MULTI-CONTAINER SYSTEM + REVERSE PROXY (CONSOLIDATION)</title>
      <dc:creator>Bala Audu Musa</dc:creator>
      <pubDate>Sat, 27 Dec 2025 15:44:42 +0000</pubDate>
      <link>https://dev.to/bala_audu_musa/multi-container-system-reverse-proxy-consolidation-1af6</link>
      <guid>https://dev.to/bala_audu_musa/multi-container-system-reverse-proxy-consolidation-1af6</guid>
      <description>&lt;p&gt;🎯 What this project consolidates&lt;/p&gt;

&lt;p&gt;You already know &lt;strong&gt;CI/CD&lt;/strong&gt;.&lt;br&gt;
Now we consolidate runtime architecture.&lt;/p&gt;

&lt;p&gt;You will practice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Docker Compose&lt;/strong&gt; (real-world usage)&lt;/li&gt;
&lt;li&gt;Service-to-service communication&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reverse proxying with Nginx&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Port isolation (security thinking)&lt;/li&gt;
&lt;li&gt;Clean project structure&lt;/li&gt;
&lt;li&gt;Debugging container networking (a core DevOps skill)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🧱 &lt;strong&gt;What we will build&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Browser
   ↓
Nginx (port 8080)
   ↓
App container (internal only)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📂 &lt;strong&gt;Project structure (professional)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;project-2-multicontainer/
├── app/
│   ├── app.js
│   ├── package.json
│   └── Dockerfile
├── nginx/
│   └── nginx.conf
├── docker-compose.yml
└── README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🧪 &lt;strong&gt;Outcome (what you should be able to say)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“I run applications behind an Nginx reverse proxy using Docker Compose, isolating services and exposing only the gateway.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;🧱 &lt;strong&gt;CLASS 1 — PROJECT SETUP (START HERE)&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Step 1: Create project directory&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd ~/OneDrive/Desktop
mkdir project-2-multicontainer-v2
cd project-2-multicontainer-v2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Initialize git:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2: Create folders&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3: Create docker-compose.yml&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;code docker-compose.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paste exactly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;services:
  app:
    build: ./app
    container_name: app
    expose:
      - "3000"

  nginx:
    image: nginx:alpine
    container_name: nginx
    ports:
      - "8080:80"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      - app

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

&lt;/div&gt;



&lt;p&gt;Save.&lt;/p&gt;

&lt;p&gt;🧱 &lt;strong&gt;PROJECT 2 v2 — CLASS 2&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Build the App Container + Configure Nginx Reverse Proxy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Goal:&lt;/strong&gt; When you open &lt;code&gt;http://localhost:8080&lt;/code&gt;, you see a message served by the &lt;strong&gt;app container&lt;/strong&gt;, through &lt;strong&gt;Nginx&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1) Create the Node app (inside app/)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Go into app folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd app
npm init -y
npm i express
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create app.js:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Paste:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const express = require("express");
const app = express();

app.get("/", (req, res) =&amp;gt; {
  res.send("Hello from app container (Project 2 v2) ✅");
});

app.listen(3000, () =&amp;gt; console.log("App running on port 3000"));

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

&lt;/div&gt;



&lt;p&gt;Create Dockerfile (inside app/):&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Paste:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM node:18-alpine

WORKDIR /app

COPY package*.json ./
RUN npm ci --only=production

COPY . .

EXPOSE 3000

CMD ["node", "app.js"]

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

&lt;/div&gt;



&lt;p&gt;Go back to project root:&lt;br&gt;
&lt;/p&gt;

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

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2) Create Nginx config (inside nginx/)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create nginx/nginx.conf:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Paste:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;events {}

http {
  server {
    listen 80;

    location / {
      proxy_pass http://app:3000;
    }
  }
}

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

&lt;/div&gt;



&lt;p&gt;✅ Key part: proxy_pass &lt;a href="http://app:3000" rel="noopener noreferrer"&gt;http://app:3000&lt;/a&gt;;&lt;/p&gt;

&lt;p&gt;app is the service name from &lt;strong&gt;docker-compose&lt;/strong&gt;.&lt;br&gt;
At this stage make sure your &lt;strong&gt;Docker Desktop&lt;/strong&gt; is up and running.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3) Run the stack&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;From project root:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker compose up --build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open browser:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://localhost:8080" rel="noopener noreferrer"&gt;http://localhost:8080&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Expected:&lt;br&gt;
Hello from app container (Project 2 v2) ✅&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F70xriva1d5l472jmw5hs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F70xriva1d5l472jmw5hs.png" alt=" " width="800" height="198"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Stop:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Then clean up:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvk3b2k0a6o8qxs3nfdcj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvk3b2k0a6o8qxs3nfdcj.png" alt=" " width="726" height="120"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🧱 &lt;strong&gt;PROJECT 2 v2 — CLASS 3&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Add Health Checks + Make Nginx “Production-ish”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Goal:&lt;/strong&gt; Add /health endpoint + improve Nginx proxy settings + verify using curl and logs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1) Add /health endpoint (App)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Open app/app.js:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Update it to this (keep your existing / route too):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const express = require("express");
const app = express();

app.get("/", (req, res) =&amp;gt; {
  res.send("Hello from app container (Project 2 v2) ✅");
});

app.get("/health", (req, res) =&amp;gt; {
  res.status(200).send("OK");
});

app.listen(3000, () =&amp;gt; console.log("App running on port 3000"));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2) Improve Nginx config (headers + timeouts)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Open:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Replace with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;events {}

http {
  upstream app_upstream {
    server app:3000;
  }

  server {
    listen 80;

    location / {
      proxy_pass http://app_upstream;

      proxy_http_version 1.1;
      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $scheme;

      proxy_connect_timeout 5s;
      proxy_read_timeout 30s;
      proxy_send_timeout 30s;
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3) Rebuild and run&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;From project root:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker compose up --build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4) Verify via curl (proof)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In a new terminal tab:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -i http://localhost:8080/
curl -i http://localhost:8080/health
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/ returns 200 and your message
/health returns OK
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F32c83bgssyf05pksc68x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F32c83bgssyf05pksc68x.png" alt=" " width="733" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5) Check logs (bonus skill)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker compose logs nginx --tail 20
docker compose logs app --tail 20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftw8hajm4qc8aut50oigo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftw8hajm4qc8aut50oigo.png" alt=" " width="736" height="467"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6) Stop and clean&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Ctrl + C&lt;/code&gt; then:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2p6cl00sg323qq2tufks.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2p6cl00sg323qq2tufks.png" alt=" " width="750" height="145"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🧱 &lt;strong&gt;PROJECT 2 v2 — CLASS 4&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Publish to GitHub + Add CI (recruiter-ready)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Goal:&lt;/strong&gt; Put this project on &lt;strong&gt;GitHub&lt;/strong&gt; with a clean &lt;code&gt;README&lt;/code&gt;and a CI workflow that validates the &lt;strong&gt;Node app&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1) Initialize git (if not already) + check status&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;From project root (project-2-multicontainer-v2):&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;If it says “not a git repository”, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git init
git branch -M main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2) Create a recruiter-friendly README (short, strong)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create/open:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Paste:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Project 2 v2 — Multi-Container App with Nginx Reverse Proxy (Docker Compose)

A production-style multi-container setup where a Node.js app runs privately behind an Nginx reverse proxy.

## Architecture
Browser → Nginx (8080) → App (internal:3000)

## What this demonstrates
- Docker Compose orchestration
- Reverse proxying with Nginx
- Service-to-service networking via Compose
- Health checks (`/health`) for operational readiness

## Run locally

`docker compose up --build`

**3) Run curl in a NEW terminal tab/window**

Open a new Git Bash window/tab and run:

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

&lt;/div&gt;



&lt;p&gt;curl -i &lt;a href="http://localhost:8080/health" rel="noopener noreferrer"&gt;http://localhost:8080/health&lt;/a&gt;&lt;br&gt;
curl -i &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
**4) Stop containers when done**

Go back to the terminal running compose and press:

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

&lt;/div&gt;



&lt;p&gt;Ctrl + C&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
Then clean up:

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

&lt;/div&gt;



&lt;p&gt;docker compose down&lt;/p&gt;



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

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

&lt;/div&gt;

</description>
      <category>reverseproxy</category>
      <category>nginx</category>
      <category>dockercompose</category>
      <category>security</category>
    </item>
    <item>
      <title>CI/CD Pipeline for a Dockerized App on AWS (From zero to production).</title>
      <dc:creator>Bala Audu Musa</dc:creator>
      <pubDate>Thu, 25 Dec 2025 19:53:20 +0000</pubDate>
      <link>https://dev.to/bala_audu_musa/cicd-pipeline-for-a-dockerized-app-on-aws-from-zero-to-production-2gdg</link>
      <guid>https://dev.to/bala_audu_musa/cicd-pipeline-for-a-dockerized-app-on-aws-from-zero-to-production-2gdg</guid>
      <description>&lt;p&gt;At the end of the project, you should be able to confidently say to your potential employer: &lt;/p&gt;

&lt;p&gt;&lt;em&gt;"I built a CI/CD pipeline using GitHub Actions to automatically test, build, and deploy a Dockerized application to AWS EC2, using Nginx and a blue/green strategy to achieve zero-downtime deployments."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 0.1 — Create a new project folder&lt;/strong&gt;&lt;br&gt;
On your local machine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd ~/OneDrive/Desktop
mkdir start-project1-cicd-from-scratch
cd start-project1-cicd-from-scratch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Initialize git:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 0.2 — Create a NEW GitHub repository&lt;/strong&gt;&lt;br&gt;
Go to 👉 &lt;a href="https://github.com/new" rel="noopener noreferrer"&gt;https://github.com/new&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repository name:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;start-project1-cicd-from-scratch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Visibility: &lt;strong&gt;Public&lt;/strong&gt;&lt;br&gt;
❌ Do NOT add README&lt;br&gt;
❌ Do NOT add .gitignore&lt;br&gt;
Create the repo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F16112ju8xtfpbjt3ff33.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F16112ju8xtfpbjt3ff33.png" alt=" " width="800" height="246"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then connect local → GitHub:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git remote add origin https://github.com/dr-musa-bala/start-project1-cicd-from-scratch.git
git branch -M main

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 0.3 — Confirm clean state&lt;/strong&gt;&lt;br&gt;
Run:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;You should see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;On branch main
No commits yet
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ This is perfect.&lt;/p&gt;

&lt;p&gt;🧱 &lt;strong&gt;PHASE 1 — Build the Minimal Node App (the “deploy target”)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Goal:&lt;/strong&gt; Create a tiny app + test so CI has something real to run.&lt;br&gt;
&lt;strong&gt;1) Create the project files&lt;/strong&gt;&lt;br&gt;
From inside &lt;code&gt;start-project1-from-scratch&lt;/code&gt; run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm init -y
npm i express
npm i -D jest supertest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2) Create&lt;/strong&gt; &lt;code&gt;app.js&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Paste:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const express = require("express");
const app = express();

app.get("/", (req, res) =&amp;gt; {
  res.send("Project 1: CI/CD from scratch ✅");
});

app.get("/health", (req, res) =&amp;gt; {
  res.status(200).send("OK");
});

module.exports = app;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;*&lt;em&gt;3) Create *&lt;/em&gt;&lt;code&gt;server.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Paste:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const app = require("./app");

const PORT = process.env.PORT || 3000;

app.listen(PORT, () =&amp;gt; {
  console.log(`Server running on port ${PORT}`);
});

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4) Create a test file&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create folder + test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir test
code test/app.test.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paste:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const request = require("supertest");
const app = require("../app");

describe("GET /", () =&amp;gt; {
  it("should return 200", async () =&amp;gt; {
    const res = await request(app).get("/");
    expect(res.statusCode).toBe(200);
  });
});

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5) Update &lt;code&gt;package.json&lt;/code&gt;scripts&lt;/strong&gt;&lt;br&gt;
Open:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Replace the &lt;code&gt;scripts&lt;/code&gt; section with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"scripts": {
  "start": "node server.js",
  "test": "jest"
}

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6) Run locally (must pass)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;You should now see output like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PASS  test/app.test.js
✓ should return 200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feh61a3nplxr8105wj3cj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feh61a3nplxr8105wj3cj.png" alt=" " width="715" height="180"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Open in browser:&lt;br&gt;
&lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should see:&lt;br&gt;
&lt;strong&gt;Project 1: CI/CD from scratch&lt;/strong&gt; ✅&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4xi1o52w53bug6falpxf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4xi1o52w53bug6falpxf.png" alt=" " width="800" height="97"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Stop server with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ctrl + C&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🧱 &lt;strong&gt;PHASE 2 — Dockerize the App (so CI/CD can ship it)&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Goal:&lt;/strong&gt; Package your app into a Docker image that runs the same everywhere.&lt;br&gt;
&lt;strong&gt;1) Create &lt;code&gt;Dockerfile&lt;/code&gt; (in project root)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Run:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;This opens up VS Code.&lt;br&gt;
Paste:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM node:18-alpine

WORKDIR /app

COPY package*.json ./
RUN npm ci --only=production

COPY . .

EXPOSE 3000

CMD ["npm", "start"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Control + S&lt;/strong&gt; to save.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2) Create &lt;code&gt;.dockerignore&lt;/code&gt; (keeps image clean)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Paste:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node_modules
npm-debug.log
.git
.github
Dockerfile
docker-compose.yml
README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3) Create &lt;code&gt;docker-compose.yml&lt;/code&gt; (local run)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;code docker-compose.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paste:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;services:
  app:
    build: .
    ports:
      - "3000:3000"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ensure at this stage that your &lt;strong&gt;Docker Desktop&lt;/strong&gt; is powered on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4) Build + run with Docker Compose&lt;/strong&gt;&lt;br&gt;
From project root:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker compose up --build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Test in browser:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You should see:&lt;br&gt;
&lt;strong&gt;Project 1: CI/CD from scratch&lt;/strong&gt; ✅&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw9nmb4dr1q113fi70uyp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw9nmb4dr1q113fi70uyp.png" alt=" " width="800" height="132"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Stop:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ctrl + C&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then clean up:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;🧱 &lt;strong&gt;PHASE 3 — Push to GitHub + Add CI (GitHub Actions)&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Goal:&lt;/strong&gt; Every push runs tests automatically. If tests fail → pipeline fails.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1) Commit and push your current code&lt;/strong&gt;&lt;br&gt;
From project root:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git add .
git commit -m "Phase 2: Add Node app + tests + Docker setup"
git push -u origin main

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

&lt;/div&gt;



&lt;p&gt;Got an error.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhxkcq6f14g0zlhvrhaxz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhxkcq6f14g0zlhvrhaxz.png" alt=" " width="738" height="93"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Git is telling you the truth:&lt;/p&gt;

&lt;p&gt;“I’m trying to push to a repository that does not exist at that URL.”&lt;/p&gt;

&lt;p&gt;So either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the GitHub repo was not created, or&lt;/li&gt;
&lt;li&gt;the repo name is slightly different from what your local git thinks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We’ll fix this cleanly.&lt;/p&gt;

&lt;p&gt;✅ STEP 1 — Check what remote URL Git is using&lt;/p&gt;

&lt;p&gt;Run:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F91fdtd6i5vlyf2njogr3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F91fdtd6i5vlyf2njogr3.png" alt=" " width="722" height="90"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From the picture illustration above we can see where the problem is coming from wrong repo (repo not tallying).&lt;/p&gt;

&lt;p&gt;Lets reset repo.&lt;br&gt;
Enter the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git remote set-url origin https://github.com/dr-musa-bala/start-project1-cicd-from-scratch.git
git remote -v
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvhbdlcy8qo3auberirb9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvhbdlcy8qo3auberirb9.png" alt=" " width="723" height="185"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we push again;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git push -u origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F31g8u1f44s3lbv58gx38.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F31g8u1f44s3lbv58gx38.png" alt=" " width="740" height="212"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check github under same repository.&lt;/p&gt;

&lt;p&gt;🧱 &lt;strong&gt;PHASE 3 (CONT.) — Add GitHub Actions CI&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;1) Create the workflow file&lt;/strong&gt;&lt;br&gt;
From your project root:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir -p .github/workflows
code .github/workflows/ci.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paste this:&lt;br&gt;
&lt;/p&gt;

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

on:
  push:
    branches: ["main"]
  pull_request:

jobs:
  test:
    runs-on: ubuntu-latest

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

      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version: "18"
          cache: "npm"

      - name: Install dependencies
        run: npm ci

      - name: Run tests
        run: npm test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2) Commit + push&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git add .github/workflows/ci.yml
git commit -m "Add GitHub Actions CI pipeline"
git push
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3) Verify it’s running&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Go to your GitHub repo → &lt;strong&gt;Actions&lt;/strong&gt; tab → you should see a workflow run.&lt;/p&gt;

&lt;p&gt;✅ If it turns green, you’re done.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs8d8astwn07wtperv91x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs8d8astwn07wtperv91x.png" alt=" " width="800" height="146"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;✅ That means Project 1 now has real CI.&lt;/p&gt;

&lt;p&gt;Now we level it up into &lt;strong&gt;CD&lt;/strong&gt;: build a &lt;strong&gt;Docker image&lt;/strong&gt; in CI and push it to **Docker Hub **automatically.&lt;/p&gt;

&lt;p&gt;🧱 &lt;strong&gt;PHASE 4 — Docker Hub Build &amp;amp; Push (CD starts)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;0) One-time setup on Docker Hub (important)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You need:&lt;/p&gt;

&lt;p&gt;Docker Hub &lt;strong&gt;username&lt;/strong&gt;&lt;br&gt;
Docker Hub &lt;strong&gt;Access Token&lt;/strong&gt; (not your password)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create the token&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Docker Hub → &lt;strong&gt;Account Settings&lt;/strong&gt; → &lt;strong&gt;Security&lt;/strong&gt; → &lt;strong&gt;New Access Token&lt;/strong&gt;&lt;br&gt;
Name it: &lt;code&gt;github-actions-project1&lt;/code&gt;&lt;br&gt;
Copy it (you won’t see it again).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7buc37x5ob25bclu4gog.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7buc37x5ob25bclu4gog.png" alt=" " width="800" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1) Add GitHub Secrets (this is the “secret stuff” done correctly)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In your GitHub repo:&lt;br&gt;
&lt;strong&gt;Settings → Secrets and variables → Actions → New repository secret&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create &lt;strong&gt;exactly&lt;/strong&gt; these:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;DOCKERHUB_USERNAME&lt;/code&gt; = your Docker Hub username (e.g., &lt;code&gt;drmusabala&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;DOCKERHUB_TOKEN&lt;/code&gt; = the access token you generated&lt;/p&gt;

&lt;p&gt;✅ Secret &lt;em&gt;names&lt;/em&gt; are fixed (left box)&lt;br&gt;
✅ Secret &lt;em&gt;values&lt;/em&gt; are your real details (right box)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2) Update workflow to build &amp;amp; push Docker image&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Open the workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;code .github/workflows/ci.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace its content with this (CI + Docker push):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: CI/CD

on:
  push:
    branches: ["main"]
    tags:
      - "v*.*.*"
  pull_request:

jobs:
  test-build-push:
    runs-on: ubuntu-latest

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

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "18"
          cache: "npm"

      - name: Install dependencies
        run: npm ci

      - name: Run tests
        run: npm test

      - name: Log in to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Build and push Docker image
        uses: docker/build-push-action@v6
        with:
          context: .
          push: true
          tags: |
            ${{ secrets.DOCKERHUB_USERNAME }}/project1-cicd:latest

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3) Commit + push&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git add .github/workflows/ci.yml
git commit -m "Add Docker build and push to Docker Hub"
git push
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyxekm7axz3xjjagvf28o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyxekm7axz3xjjagvf28o.png" alt=" " width="800" height="521"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Very critical:&lt;/strong&gt; Make sure in your secrets, it's your Docker Hub username you are using. Because I kept using my GitHub username and keeps getting errors.&lt;/p&gt;

&lt;p&gt;You have successfully &lt;strong&gt;built&lt;/strong&gt;, tested*&lt;strong&gt;*, **containerized&lt;/strong&gt;, &lt;strong&gt;authenticated&lt;/strong&gt;, and pushed an image via CI. That’s core &lt;strong&gt;DevOps&lt;/strong&gt; skill.&lt;/p&gt;

&lt;p&gt;BONUS:&lt;br&gt;
📌 Immediate next steps (important)&lt;br&gt;
1️⃣ &lt;strong&gt;Lock this win into documentation (VERY important)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To be pasted in README.md&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🚀 **Production CI/CD Pipeline — Docker &amp;amp; GitHub Actions**

This project demonstrates my ability to design, implement, and troubleshoot a production-grade CI/CD pipeline using modern DevOps tooling.

It reflects how CI/CD is actually done in real teams, including secure credential handling, container image lifecycle management, and failure debugging — not just “happy-path” automation.

🔍 What This Project Proves

- By completing this project end-to-end, I demonstrate the ability to:
- Build automated CI pipelines triggered on source control events
- Containerize applications using Docker best practices
- Securely authenticate and push images to Docker Hub
- Manage secrets and tokens using GitHub Actions
- Debug real CI failures (auth issues, build errors, test failures)
- Think in terms of repeatability, security, and automation
- This is the same workflow used in real production teams — simplified, but not diluted.

🧱 Technical Stack

- CI/CD: GitHub Actions
- Containerization: Docker
- Registry: Docker Hub
- Runtime: Node.js
- OS (CI runners): Linux
- Version Control: Git &amp;amp; GitHub
- 🔁 CI/CD Workflow (High-Level)

The pipeline automatically runs on every push to main.

- Pipeline Stages:
- Source checkout
- Node.js environment setup
- Dependency installation
- Test execution
- Secure login to Docker Hub
- Docker image build
- Docker image push to registry

📍 Workflow definition:

.github/workflows/ci.yml

🐳 Docker Image Automation

- The application is built into a Docker image and published automatically.
- Image build is fully automated
- Authentication uses Docker Hub access tokens
- No credentials are committed to source control

Example:

docker pull &amp;lt;dockerhub-username&amp;gt;/start-project1-cicd-from-scratch:latest

🔐 Security Practices

- Security was treated as a first-class concern, not an afterthought.
- Secrets stored in GitHub Actions Secrets
- Docker Hub authentication via access token, not password
- No sensitive data committed to Git
- Pipeline follows least-privilege principles

Secrets used:

DOCKERHUB_USERNAME

DOCKERHUB_TOKEN

📂 Repository Structure
.
├── .github/workflows/ci.yml   # CI pipeline definition
├── Dockerfile                # Production-ready Docker image
├── docker-compose.yml        # Local orchestration
├── index.js                  # Application entry point
├── package.json              # Dependencies &amp;amp; scripts
└── README.md

🧪 Testing Philosophy

- Tests are executed automatically during CI
- Pipeline fails fast if tests fail
- Enforces discipline expected in real engineering teams
- This models quality gates commonly used in production pipelines.

🧠 Engineering Mindset Demonstrated

This project emphasizes:

- Automation over manual steps
- Secure-by-default configuration
- Debugging over blind copy-paste
- Reproducibility across environments
- Clear separation between build, test, and release stages

🚀 Why This Matters to Employers

This project shows I can:

- Contribute to existing CI/CD systems
- Own small-to-medium automation tasks independently
- Understand how code moves from commit → container → registry
- Communicate infrastructure clearly through code and documentation
- It forms a strong foundation for:
- Continuous Deployment (CD)
- Cloud deployments (EC2, ECS, Kubernetes)
- Infrastructure as Code (Terraform)

📈 Next Steps (Planned Enhancements)

- Automated deployment to cloud (EC2)
- Zero-downtime deployment strategies
- Monitoring &amp;amp; health checks
- Infrastructure provisioning with Terraform

👤 About Me

**Dr. Musa Bala Audu**
Junior DevOps Engineer — Open to Remote Roles
GitHub: https://github.com/dr-musa-bala
Dev.to: https://dev.to/bala_audu_musa
Hashnode: https://hashnode.com/@musabalaaudu
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your README should include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Project overview&lt;/li&gt;
&lt;li&gt;CI workflow explanation&lt;/li&gt;
&lt;li&gt;Docker image link&lt;/li&gt;
&lt;li&gt;What problem it solves&lt;/li&gt;
&lt;li&gt;What you learned&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✅ Step 1: Make sure you are in the project directory&lt;/p&gt;

&lt;p&gt;In Git Bash, run:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;You should see something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/Users/fresh/OneDrive/Desktop/start-project1-cicd-from-scratch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If not, go there:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd ~/OneDrive/Desktop/start-project1-cicd-from-scratch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ Step 2: Confirm README exists&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;You must see:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;If you don’t, create it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ &lt;strong&gt;Step 3: Open README and paste the content&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Open with VS Code (recommended):&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;👉 Paste the recruiter-tailored README I wrote for you&lt;br&gt;
👉 Save the file (Ctrl + S)&lt;br&gt;
👉 Close the editor&lt;/p&gt;

&lt;p&gt;✅ Step 4: Stage the README&lt;br&gt;
git add README.md&lt;/p&gt;

&lt;p&gt;Check status:&lt;/p&gt;

&lt;p&gt;git status&lt;/p&gt;

&lt;p&gt;You should see:&lt;/p&gt;

&lt;p&gt;new file:   README.md&lt;/p&gt;

&lt;p&gt;or&lt;/p&gt;

&lt;p&gt;modified:  README.md&lt;/p&gt;

&lt;p&gt;✅ Step 5: Commit the README (important message)&lt;/p&gt;

&lt;p&gt;Use a professional commit message:&lt;/p&gt;

&lt;p&gt;git commit -m "docs: add production-grade README for CI/CD project"&lt;/p&gt;

&lt;p&gt;✅ Step 6: Push to GitHub&lt;br&gt;
git push origin main&lt;/p&gt;

&lt;p&gt;If main is already tracking:&lt;/p&gt;

&lt;p&gt;git push&lt;/p&gt;

&lt;p&gt;✅ Step 7: Verify on GitHub&lt;/p&gt;

&lt;p&gt;Open your repo in browser&lt;/p&gt;

&lt;p&gt;Refresh the page&lt;/p&gt;

&lt;p&gt;You should see:&lt;/p&gt;

&lt;p&gt;README rendered automatically&lt;/p&gt;

&lt;p&gt;Professional project overview visible to recruiters&lt;/p&gt;

</description>
      <category>docker</category>
      <category>cicd</category>
      <category>automation</category>
      <category>nginx</category>
    </item>
    <item>
      <title>Provisioning AWS Infrastructure Using Terraform (IaC)</title>
      <dc:creator>Bala Audu Musa</dc:creator>
      <pubDate>Mon, 22 Dec 2025 18:27:42 +0000</pubDate>
      <link>https://dev.to/bala_audu_musa/provisioning-aws-infrastructure-using-terraform-iac-508j</link>
      <guid>https://dev.to/bala_audu_musa/provisioning-aws-infrastructure-using-terraform-iac-508j</guid>
      <description>&lt;p&gt;6 million dollar question: &lt;em&gt;“If everything went down today, could you rebuild it from code?”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;After this project, the answer is YES.&lt;/p&gt;

&lt;p&gt;🎯 &lt;strong&gt;PROJECT 3 — GOALS&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;By the end of this project, you will:&lt;/li&gt;
&lt;li&gt;Provision AWS infrastructure entirely from code&lt;/li&gt;
&lt;li&gt;Create and destroy EC2 safely using Terraform&lt;/li&gt;
&lt;li&gt;Manage Security Groups declaratively&lt;/li&gt;
&lt;li&gt;Understand Terraform state (very important)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Be able to say (confidently):&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“I provision AWS infrastructure using Terraform.”&lt;/em&gt;&lt;br&gt;
📦 WHAT WE WILL BUILD (CLEAR SCOPE)&lt;/p&gt;

&lt;p&gt;Terraform will create:&lt;/p&gt;

&lt;p&gt;✅ EC2 instance (Ubuntu)&lt;/p&gt;

&lt;p&gt;✅ Security Group&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SSH (22)&lt;/li&gt;
&lt;li&gt;HTTP (80)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✅ Key Pair (or reference existing)&lt;/p&gt;

&lt;p&gt;✅ Output values (public IP)&lt;/p&gt;

&lt;p&gt;This will replace manual EC2 creation.&lt;/p&gt;

&lt;p&gt;🗂 PROJECT STRUCTURE (PROFESSIONAL)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;project-3-terraform-aws/
├── main.tf
├── variables.tf
├── outputs.tf
├── terraform.tfvars
└── README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;NB: Note that we are using Bash terminal throughout the project except stated otherwise.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;🧱 CLASS 1 — TERRAFORM SETUP &amp;amp; BASICS&lt;br&gt;
Step 1: Install Terraform (Windows)&lt;/p&gt;

&lt;p&gt;Download:&lt;br&gt;
👉 &lt;a href="https://developer.hashicorp.com/terraform/downloads" rel="noopener noreferrer"&gt;https://developer.hashicorp.com/terraform/downloads&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Choose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Windows AMD64&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Extract terraform.exe&lt;/li&gt;
&lt;li&gt;Add it to PATH&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;How do you add to path?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;🧱 STEP 4 — ADD TERRAFORM TO PATH (CRITICAL)&lt;/p&gt;

&lt;p&gt;This is the step most people miss.&lt;/p&gt;

&lt;p&gt;3️⃣ Add &lt;code&gt;C:\terraform&lt;/code&gt; to PATH (CRITICAL)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Press &lt;strong&gt;Windows key&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Search: &lt;strong&gt;Environment Variables&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Open &lt;strong&gt;Edit the system environment variables&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Environment Variables&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;System variables&lt;/strong&gt;, select &lt;strong&gt;Path&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Edit&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;New&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Click on &lt;strong&gt;Browse..&lt;/strong&gt; and select the &lt;strong&gt;terraform folder&lt;/strong&gt; we have save in &lt;strong&gt;C:.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;OK&lt;/strong&gt; on all &lt;strong&gt;windows&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;⚠️ You must &lt;strong&gt;close and reopen&lt;/strong&gt; Git Bash after this. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhe6vcyel2sl8d04lte0r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhe6vcyel2sl8d04lte0r.png" alt=" " width="596" height="645"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🧪 STEP 5 — VERIFY INSTALLATION&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Close all terminals&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Open &lt;strong&gt;Git Bash&lt;/strong&gt; again, then run:&lt;br&gt;
Verify:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;You must see a version number.&lt;/p&gt;

&lt;p&gt;✅ STEP 2: Create the Terraform project directory&lt;/p&gt;

&lt;p&gt;Now create it:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mkdir project-3-terraform-aws&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Enter it:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cd project-3-terraform-aws&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Confirm:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pwd&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You should see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.../Desktop/project-3-terraform-aws
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ Now you’re in the right place.&lt;/p&gt;

&lt;p&gt;☁️ AWS SETUP — KEY PAIR (SAFE &amp;amp; CORRECT)&lt;br&gt;
🎯 What we are doing&lt;/p&gt;

&lt;p&gt;By the end of this, you will have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An &lt;strong&gt;AWS account&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;EC2 Key Pair&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;A .pem file saved safely&lt;/li&gt;
&lt;li&gt;The key pair &lt;strong&gt;NAME&lt;/strong&gt; ready for &lt;strong&gt;Terraform&lt;/strong&gt;
⚠️ We are NOT creating &lt;strong&gt;EC2&lt;/strong&gt; yet — just preparing access.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;STEP 1: &lt;strong&gt;Log in&lt;/strong&gt; to &lt;strong&gt;AWS Console&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Go to:&lt;br&gt;
👉 &lt;a href="https://console.aws.amazon.com/" rel="noopener noreferrer"&gt;https://console.aws.amazon.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sign in with your *&lt;em&gt;AWS account.&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
STEP 2: Select the correct region (IMPORTANT)&lt;/p&gt;

&lt;p&gt;Top-right corner of AWS Console:&lt;/p&gt;

&lt;p&gt;Select &lt;strong&gt;US East (N. Virginia)&lt;/strong&gt; → &lt;code&gt;us-east-1&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Free-tier friendly&lt;/li&gt;
&lt;li&gt;Matches our Terraform default&lt;/li&gt;
&lt;li&gt;Most tutorials &amp;amp; AMIs work here&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;STEP 3: &lt;strong&gt;Go to EC2 Dashboard&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the AWS search bar, type:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;EC2&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;EC2&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;STEP 4: Create a &lt;strong&gt;Key Pair&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the left sidebar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Network &amp;amp; Security → Key Pairs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Click &lt;strong&gt;Create key pair.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fill the form:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Name:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;terraform-key&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;(simple, professional, reusable)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key pair type&lt;/strong&gt;: RSA&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Private key file format:&lt;/strong&gt; .pem&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Create key pair&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;STEP 5: SAVE THE KEY FILE (VERY IMPORTANT)&lt;/p&gt;

&lt;p&gt;Your browser will download:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;terraform-key.pem&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Do NOT delete it&lt;/p&gt;

&lt;p&gt;Do NOT rename it&lt;/p&gt;

&lt;p&gt;⚠️ AWS will never show this file again.&lt;/p&gt;

&lt;p&gt;✅ STEP 3: Initialize the &lt;strong&gt;project files&lt;/strong&gt;&lt;br&gt;
Create the &lt;strong&gt;Terraform files&lt;/strong&gt; we’ll use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;`touch main.tf variables.tf outputs.tf terraform.tfvars`

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

&lt;/div&gt;



&lt;p&gt;Confirm:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ls&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You should see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;main.tf  variables.tf  outputs.tf  terraform.tfvars
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that the folder exists and files are created, open it in &lt;strong&gt;VS Code&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Step 1: Paste &lt;code&gt;variables.tf&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Open &lt;code&gt;variables.tf&lt;/code&gt; and paste:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;variable "region" {&lt;br&gt;
  description = "AWS region"&lt;br&gt;
  type        = string&lt;br&gt;
  default     = "us-east-1"&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;variable "instance_type" {&lt;br&gt;
  description = "EC2 instance type (keep low-cost)"&lt;br&gt;
  type        = string&lt;br&gt;
  default     = "t2.micro"&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;variable "key_name" {&lt;br&gt;
  description = "Existing AWS key pair name (NOT the .pem filename)"&lt;br&gt;
  type        = string&lt;br&gt;
}&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
Step 2: Paste `main.tf`

Open `main.tf `and paste:

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

&lt;/div&gt;



&lt;p&gt;terraform {&lt;br&gt;
  required_providers {&lt;br&gt;
    aws = {&lt;br&gt;
      source  = "hashicorp/aws"&lt;br&gt;
      version = "~&amp;gt; 5.0"&lt;br&gt;
    }&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;provider "aws" {&lt;br&gt;
  region = var.region&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;resource "aws_security_group" "web_sg" {&lt;br&gt;
  name        = "terraform-web-sg"&lt;br&gt;
  description = "Allow SSH and HTTP"&lt;/p&gt;

&lt;p&gt;ingress {&lt;br&gt;
    description = "SSH"&lt;br&gt;
    from_port   = 22&lt;br&gt;
    to_port     = 22&lt;br&gt;
    protocol    = "tcp"&lt;br&gt;
    cidr_blocks = ["0.0.0.0/0"]&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;ingress {&lt;br&gt;
    description = "HTTP"&lt;br&gt;
    from_port   = 80&lt;br&gt;
    to_port     = 80&lt;br&gt;
    protocol    = "tcp"&lt;br&gt;
    cidr_blocks = ["0.0.0.0/0"]&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;egress {&lt;br&gt;
    from_port   = 0&lt;br&gt;
    to_port     = 0&lt;br&gt;
    protocol    = "-1"&lt;br&gt;
    cidr_blocks = ["0.0.0.0/0"]&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;data "aws_ami" "ubuntu" {&lt;br&gt;
  most_recent = true&lt;/p&gt;

&lt;p&gt;filter {&lt;br&gt;
    name   = "name"&lt;br&gt;
    values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"]&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;filter {&lt;br&gt;
    name   = "virtualization-type"&lt;br&gt;
    values = ["hvm"]&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;owners = ["099720109477"] # Canonical (Ubuntu)&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;resource "aws_instance" "web" {&lt;br&gt;
  ami           = data.aws_ami.ubuntu.id&lt;br&gt;
  instance_type = var.instance_type&lt;br&gt;
  key_name      = var.key_name&lt;/p&gt;

&lt;p&gt;vpc_security_group_ids = [aws_security_group.web_sg.id]&lt;/p&gt;

&lt;p&gt;tags = {&lt;br&gt;
    Name = "terraform-web-instance"&lt;br&gt;
  }&lt;br&gt;
}&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Step 3: Paste `outputs.tf`

Open `outputs.tf` and paste:

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

&lt;/div&gt;



&lt;p&gt;output "public_ip" {&lt;br&gt;
  description = "Public IP of the EC2 instance"&lt;br&gt;
  value       = aws_instance.web.public_ip&lt;br&gt;
}&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
Step 4: Set `terraform.tfvars`

Open `terraform.tfvars` and paste (edit the key name):

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

&lt;/div&gt;



&lt;p&gt;key_name = "&lt;code&gt;YOUR_KEYPAIR_NAME&lt;/code&gt;"&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
⚠️ This must be your AWS Key Pair name (example: nodejs-key) — not nodejs-key.pem.

Step 5: Run Terraform commands (from Git Bash in project-3 folder)

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

&lt;/div&gt;



&lt;p&gt;terraform init&lt;br&gt;
terraform fmt&lt;br&gt;
terraform validate&lt;br&gt;
terraform plan&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;STEP 6: Confirm the **Key Pair** exists

Back in `AWS Console → Key Pairs`

You should see:

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

&lt;/div&gt;



&lt;p&gt;terraform-key&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;👉 Terraform uses the **name**
👉 SSH uses the **.pem file**

STEP 7: Prepare for **Terraform**

Now go back to your local machine.

Open:

`project-3-terraform-aws/terraform.tfvars`


Set:

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

&lt;/div&gt;



&lt;p&gt;key_name = "terraform-key"&lt;br&gt;
&lt;/p&gt;

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

✅ This is correct.

🚀 PROJECT 3 — CLASS 2 (CONTINUED)
Terraform Plan → Apply → Verify → Destroy (Cost-Safe)

You already have:

✅ Terraform installed

✅ AWS CLI configured

✅ Key pair created: terraform-key

✅ Terraform files created

Now we proceed.

✅ **Step 1: Set the key pair in Terraform**

Open `terraform.tfvars` and confirm it contains exactly:

`key_name = "terraform-key"`

Save the file.

✅ FIX AWS CLI v2 (Windows 11)

Step 1: Check if AWS CLI files actually exist

Open File Explorer and go to:

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

&lt;/div&gt;



&lt;p&gt;C:\Program Files\Amazon\AWSCLIV2\&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
Look for:

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

&lt;/div&gt;



&lt;p&gt;aws.exe&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
Also check this folder:

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

&lt;/div&gt;



&lt;p&gt;C:\Program Files\Amazon\AWSCLIV2\bin\&lt;br&gt;
&lt;/p&gt;

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

Look for:

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

&lt;/div&gt;



&lt;p&gt;aws.exe&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
How to add PATH:

Press **Win key** → type **Environment Variables**

Open **Edit the system environment variables**

Click **Environment Variables…**

Under User variables (top), select **Path** → **Edit**

New → paste the path above

**OK → OK → OK**

✅ Now close ALL terminals (PowerShell + Git Bash) and reopen PowerShell.

Test:

**where aws
aws --version**

**After AWS works: configure creds for Terraform**

Once `aws --version` works, do:

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

&lt;/div&gt;



&lt;p&gt;aws configure&lt;br&gt;
&lt;/p&gt;

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

region: `us-east-1
`
output: `json`

Then confirm:

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

&lt;/div&gt;



&lt;p&gt;aws sts get-caller-identity&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
Then go back to your **Terraform folder** and **run**:

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

&lt;/div&gt;



&lt;p&gt;terraform plan&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Expected output (example):

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

&lt;/div&gt;



&lt;p&gt;C:\Program Files\Amazon\AWSCLIV2\aws.exe&lt;br&gt;
aws-cli/2.xx.x Python/3.xx Windows/10 exe/AMD64&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✅ **Then continue Project 3 (Terraform AWS)**
Configure AWS credentials:

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

&lt;/div&gt;



&lt;p&gt;aws configure&lt;br&gt;
&lt;/p&gt;

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

**Access Key ID** → from AWS IAM
**Secret Access Key** → from AWS IAM
**Region** → `us-east-1`
**Output** → `json`

Verify:

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

&lt;/div&gt;



&lt;p&gt;aws sts get-caller-identity&lt;br&gt;
&lt;/p&gt;

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

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

&lt;/div&gt;



&lt;p&gt;Copy code&lt;br&gt;
terraform init&lt;br&gt;
terraform plan&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You should get a successful result.

![ ](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5nmvwgspcd28m35yxgap.png)

**Next step (Project 3)**

From the same folder `(~/OneDrive/Desktop/project-3-terraform-aws)` run:

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

&lt;/div&gt;



&lt;p&gt;terraform apply&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
Type **yes **when it asks.

After it finishes, **run**:

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

&lt;/div&gt;



&lt;p&gt;terraform output&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
You should see the 

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

&lt;/div&gt;



&lt;p&gt;public_ip&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
**1) Get the EC2 Public IP**

![ ](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6gwnfgstg8rlqvp0a7kf.png)

Run (in the same project folder):

terraform output public_ip

If it says “no outputs found”, run:

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

&lt;/div&gt;



&lt;p&gt;terraform refresh&lt;br&gt;
terraform output&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
(That will display it.)

Then we test it

1) SSH into the server (Git Bash)

Your keypair name is terraform-key, so your file is likely on Desktop.

Run:

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

&lt;/div&gt;



&lt;p&gt;chmod 400 ~/OneDrive/Desktop/terraform-key.pem&lt;br&gt;
ssh -i ~/OneDrive/Desktop/terraform-key.pem &lt;a href="mailto:ubuntu@34.229.201.13"&gt;ubuntu@34.229.201.13&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
If your key is in **Downloads** instead:

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

&lt;/div&gt;



&lt;p&gt;chmod 400 ~/Downloads/terraform-key.pem&lt;br&gt;
ssh -i ~/Downloads/terraform-key.pem &lt;a href="mailto:ubuntu@34.229.201.13"&gt;ubuntu@34.229.201.13&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
2) Once you’re inside EC2: install Docker and run the proof app

Paste these **exactly**:

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

&lt;/div&gt;



&lt;p&gt;sudo apt-get update -y&lt;br&gt;
sudo apt-get install -y docker.io&lt;br&gt;
sudo systemctl enable --now docker&lt;br&gt;
sudo usermod -aG docker ubuntu&lt;br&gt;
newgrp docker&lt;br&gt;
docker run -d --name hello -p 80:80 nginx:alpine&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
Now open in your browser:

http://34.229.201.13

You should see the Nginx page ✅

![ ](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/284x0mgp2nyppdwk2obl.png)

**Destroy everything (from your Terraform folder)**

Make sure you’re in the **right folder**:

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

&lt;/div&gt;



&lt;p&gt;cd ~/OneDrive/Desktop/project-3-terraform-aws&lt;/p&gt;



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


Run:

`terraform destroy`

Type:` yes`


This will remove:

- EC2 instance
- Security Group

2) Confirm it’s gone

After it completes, run:

`terraform output`


It should either show nothing useful or error because resources are gone.

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

&lt;/div&gt;

</description>
      <category>terraform</category>
      <category>provision</category>
      <category>aws</category>
      <category>windows</category>
    </item>
    <item>
      <title>Multi-Container Web Application with Nginx Reverse Proxy and Docker Compose</title>
      <dc:creator>Bala Audu Musa</dc:creator>
      <pubDate>Sat, 20 Dec 2025 18:26:27 +0000</pubDate>
      <link>https://dev.to/bala_audu_musa/multi-container-web-application-with-nginx-reverse-proxy-and-docker-compose-db4</link>
      <guid>https://dev.to/bala_audu_musa/multi-container-web-application-with-nginx-reverse-proxy-and-docker-compose-db4</guid>
      <description>&lt;p&gt;This project demonstrates a &lt;strong&gt;production-style multi-container architecture&lt;/strong&gt; using Docker Compose, where a Node.js application is deployed &lt;strong&gt;behind an Nginx reverse proxy&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The goal of this project is to showcase &lt;strong&gt;real DevOps patterns&lt;/strong&gt;, not single-container demos.&lt;/p&gt;

&lt;h2&gt;
  
  
  🚀 &lt;strong&gt;What This Project Demonstrates&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Multi-container application design&lt;/li&gt;
&lt;li&gt;Docker Compose for service orchestration&lt;/li&gt;
&lt;li&gt;Nginx as a reverse proxy&lt;/li&gt;
&lt;li&gt;Private application containers (not exposed to the internet)&lt;/li&gt;
&lt;li&gt;Service-to-service communication via Docker networking&lt;/li&gt;
&lt;li&gt;Clean separation between application and web server&lt;/li&gt;
&lt;li&gt;Production-ready container structure&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Client (Browser)&lt;br&gt;
|&lt;br&gt;
v&lt;br&gt;
Nginx (public, port 8080)&lt;br&gt;
|&lt;br&gt;
v&lt;br&gt;
Node.js App (private, port 5000)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only &lt;strong&gt;Nginx&lt;/strong&gt; is exposed to the host&lt;/li&gt;
&lt;li&gt;The Node.js app is accessible &lt;strong&gt;only inside the Docker network&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Containers communicate using &lt;strong&gt;service names&lt;/strong&gt;, not IPs&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  📁 &lt;strong&gt;Project Structure&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;project-2-multicontainer/&lt;br&gt;
├── app/&lt;br&gt;
│ ├── Dockerfile&lt;br&gt;
│ ├── index.js&lt;br&gt;
│ ├── package.json&lt;br&gt;
│ └── package-lock.json&lt;br&gt;
├── nginx/&lt;br&gt;
│ └── nginx.conf&lt;br&gt;
├── docker-compose.yml&lt;br&gt;
└── README.md&lt;/p&gt;


&lt;h2&gt;
  
  
  ⚙️ &lt;strong&gt;Technologies Used&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Docker&lt;/li&gt;
&lt;li&gt;Docker Compose (v2)&lt;/li&gt;
&lt;li&gt;Node.js (Express)&lt;/li&gt;
&lt;li&gt;Nginx&lt;/li&gt;
&lt;li&gt;Linux-based containers&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  🛠 &lt;strong&gt;How to Run the Project Locally&lt;/strong&gt;
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Docker Desktop&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Docker Compose v2&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Steps&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Clone the repository&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/dr-musa-bala/project-2-multicontainer.git
&lt;span class="nb"&gt;cd &lt;/span&gt;project-2-multicontainer

2. &lt;span class="k"&gt;**&lt;/span&gt;Build and start the containers&lt;span class="k"&gt;**&lt;/span&gt;:

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

&lt;/div&gt;


&lt;p&gt;docker compose up --build&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
3. Open your browser:

Open your browser:

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

&lt;/div&gt;



&lt;p&gt;localhost:8080&lt;/p&gt;



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


![ ](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1i3isd39y65f8rc0ttbv.png)

🔒 **Security &amp;amp; Production Considerations**

The application container does not expose any ports to the host

All external traffic is handled by **Nginx**

This mirrors how applications are deployed in real production environments

💡 **Why This Matters (DevOps Perspective)**

This project reflects how modern DevOps teams:

- Isolate application services
- Control ingress traffic via reverse proxies
- Use declarative configuration for reproducibility
- Build systems that are easy to extend into CI/CD pipelines

🔜 **Next Improvements**

- Add CI/CD with GitHub Actions
- Push application images to Docker Hub
- Deploy the stack to AWS EC2
- Implement zero-downtime updates
- Add HTTPS with Let’s Encrypt






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

&lt;/div&gt;

</description>
      <category>docker</category>
      <category>nginx</category>
      <category>microservices</category>
      <category>compose</category>
    </item>
    <item>
      <title>I Set Up My Windows 11 Machine Once for All DevOps Projects — Here’s How.</title>
      <dc:creator>Bala Audu Musa</dc:creator>
      <pubDate>Sun, 14 Dec 2025 12:49:40 +0000</pubDate>
      <link>https://dev.to/bala_audu_musa/i-set-up-my-windows-11-machine-once-for-all-devops-projects-heres-how-14j9</link>
      <guid>https://dev.to/bala_audu_musa/i-set-up-my-windows-11-machine-once-for-all-devops-projects-heres-how-14j9</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;INTRODUCTION:&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Most people fail at &lt;strong&gt;DevOps&lt;/strong&gt; before they even begin — not because &lt;strong&gt;DevOps&lt;/strong&gt; is hard, but because their &lt;strong&gt;Windows setup&lt;/strong&gt; is broken.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Docker errors&lt;/strong&gt;. &lt;strong&gt;Git **not found. Half-installed tools.&lt;br&gt;
Instead of learning **CI/CD&lt;/strong&gt;, they spend weeks &lt;strong&gt;debugging&lt;/strong&gt; their machine.&lt;/p&gt;

&lt;p&gt;This is &lt;strong&gt;Phase 0&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;No &lt;strong&gt;pipelines&lt;/strong&gt;. No &lt;strong&gt;Kubernetes&lt;/strong&gt;. No cloud magic.&lt;br&gt;
Just a clean, one-time &lt;strong&gt;Windows 11 DevOps setup&lt;/strong&gt; that won’t break later.&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;60–90 minutes&lt;/strong&gt;, we’ll install only what’s required for real &lt;strong&gt;CI/CD projects&lt;/strong&gt;:&lt;br&gt;
&lt;strong&gt;Git&lt;/strong&gt;, &lt;strong&gt;GitHub&lt;/strong&gt;, &lt;strong&gt;Docker (WSL 2)&lt;/strong&gt;, &lt;strong&gt;Node.js&lt;/strong&gt;, &lt;strong&gt;VS Code&lt;/strong&gt;, and &lt;strong&gt;AWS CLI&lt;/strong&gt; — nothing extra.&lt;/p&gt;

&lt;p&gt;If every command works at the end, your &lt;strong&gt;foundation is solid&lt;/strong&gt;.&lt;br&gt;
From here on, everything we build is &lt;strong&gt;real proof&lt;/strong&gt;.&lt;/p&gt;



&lt;p&gt;✅&lt;strong&gt;WHAT YOU WILL HAVE AT THE END OF PHASE 0&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A working terminal&lt;/li&gt;
&lt;li&gt;Git connected to GitHub&lt;/li&gt;
&lt;li&gt;Docker running correctly&lt;/li&gt;
&lt;li&gt;Node.js ready (for the sample app)&lt;/li&gt;
&lt;li&gt;VS Code configured&lt;/li&gt;
&lt;li&gt;AWS CLI ready (but not used yet)&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;🔹** STEP 1: Install Visual Studio Code (Editor)**&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We need a &lt;strong&gt;clean, reliable editor&lt;/strong&gt;. VS Code is industry standard.&lt;/p&gt;

&lt;p&gt;👉 [&lt;a href="https://code.visualstudio.com/Download" rel="noopener noreferrer"&gt;https://code.visualstudio.com/Download&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;After Installation — Install These Extensions ONLY:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Open VS Code → Extensions (Ctrl+Shift+X)&lt;/p&gt;

&lt;p&gt;Install:&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Docker&lt;/strong&gt;&lt;br&gt;
✅ &lt;strong&gt;GitHub Pull Requests and Issues&lt;/strong&gt;&lt;br&gt;
✅ &lt;strong&gt;YAML&lt;/strong&gt;&lt;br&gt;
✅ &lt;strong&gt;Terraform&lt;/strong&gt; (for later, but safe to install now)&lt;/p&gt;

&lt;p&gt;Do &lt;strong&gt;not&lt;/strong&gt; install random themes or plugins.&lt;/p&gt;

&lt;p&gt;🔹 &lt;strong&gt;STEP 2: Install Git (Source Control)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Git is non-negotiable. Recruiters check GitHub first.&lt;/p&gt;

&lt;p&gt;Download &amp;amp; Install&lt;br&gt;
👉 [(&lt;a href="https://git-scm.com/download/win)" rel="noopener noreferrer"&gt;https://git-scm.com/download/win)&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;During installation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click &lt;strong&gt;Next&lt;/strong&gt; for everything&lt;/li&gt;
&lt;li&gt;When asked about default editor → choose &lt;strong&gt;VS Code&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;When asked about line endings → &lt;strong&gt;Checkout Windows-style, commit Unix-style&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Verify Installation&lt;/p&gt;

&lt;p&gt;Open Command Prompt or PowerShell and run:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;✅ You should see a version number.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuy84r810uk1plcvlqv9a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuy84r810uk1plcvlqv9a.png" alt=" " width="800" height="307"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;STEP 3: Create / Confirm GitHub Account&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Platform you’ll showcase everything on&lt;/p&gt;

&lt;p&gt;👉 [&lt;a href="https://github.com" rel="noopener noreferrer"&gt;https://github.com&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Actions&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create an account (if you don’t have one)&lt;/li&gt;
&lt;li&gt;Choose a &lt;strong&gt;professional username&lt;/strong&gt;
Example: &lt;code&gt;first-devops&lt;/code&gt;,&lt;code&gt;firstname-cloud&lt;/code&gt;, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;⚠️ This GitHub profile will go on your CV.&lt;/p&gt;

&lt;p&gt;🔹 &lt;strong&gt;STEP 4: Install Node.js (For Sample App)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We are &lt;strong&gt;not learning Node.js&lt;/strong&gt;.&lt;br&gt;
We only need it to &lt;strong&gt;run the app and tests&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;👉 [&lt;a href="https://nodejs.org/en/download/" rel="noopener noreferrer"&gt;https://nodejs.org/en/download/&lt;/a&gt;]&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;LTS version&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Windows Installer (.msi)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Verify&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Both should return versions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgfxsbth9lqytqbz88xzo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgfxsbth9lqytqbz88xzo.png" alt=" " width="748" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🔹 &lt;strong&gt;STEP 5: Install Docker Desktop (CRITICAL)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;CI/CD = Docker. No Docker, no DevOps.&lt;/p&gt;

&lt;p&gt;👉 [&lt;a href="https://www.docker.com/products/docker-desktop/" rel="noopener noreferrer"&gt;https://www.docker.com/products/docker-desktop/&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;During installation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enable &lt;strong&gt;WSL 2&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Allow it to install Linux kernel updates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;⚠️ You may be asked to restart your PC — &lt;strong&gt;do it&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;After Restart:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Open &lt;strong&gt;Docker Desktop&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Wait until it says: “Docker is running”&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Verify&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker --version
docker compose version

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

&lt;/div&gt;



&lt;p&gt;✅ Both must work.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmg85hvvt1cu1if375q5o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmg85hvvt1cu1if375q5o.png" alt=" " width="752" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🔹 &lt;strong&gt;STEP 6: Install AWS CLI (Preparation)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We won’t use AWS &lt;strong&gt;yet&lt;/strong&gt;, but install now to avoid breaking flow later.&lt;/p&gt;

&lt;p&gt;👉 [&lt;a href="https://aws.amazon.com/cli/" rel="noopener noreferrer"&gt;https://aws.amazon.com/cli/&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;Download:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;AWS CLI v2 – Windows&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Verify&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;You should see version info.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1sbd11mu28b4oq5pbubs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1sbd11mu28b4oq5pbubs.png" alt=" " width="747" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;⚠️ Do NOT configure credentials yet.&lt;/p&gt;

&lt;p&gt;🔹 &lt;strong&gt;STEP 7: Install Git Bash (Terminal We’ll Use)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you installed Git correctly, Git Bash is already installed.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Right-click anywhere → Git Bash&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This will be our &lt;strong&gt;main terminal&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;🔹 &lt;strong&gt;STEP 8: Quick Health Check (IMPORTANT)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Run these commands &lt;strong&gt;one by one&lt;/strong&gt; in Git Bash:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git --version
docker --version
docker compose version
node --version
npm --version
aws --version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ All must return versions&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fthbj785cjn4s5jvqsyfv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fthbj785cjn4s5jvqsyfv.png" alt=" " width="750" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note well:&lt;/strong&gt; If your environment is broken, &lt;strong&gt;everything later breaks&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>windows11</category>
      <category>cloud</category>
      <category>git</category>
    </item>
    <item>
      <title>Create an Ansible Playbook to Install Git on managed host</title>
      <dc:creator>Bala Audu Musa</dc:creator>
      <pubDate>Tue, 24 Jun 2025 19:56:47 +0000</pubDate>
      <link>https://dev.to/bala_audu_musa/create-an-ansible-playbook-to-install-git-on-managed-host-53j1</link>
      <guid>https://dev.to/bala_audu_musa/create-an-ansible-playbook-to-install-git-on-managed-host-53j1</guid>
      <description>&lt;p&gt;&lt;strong&gt;Project Introduction:&lt;/strong&gt;&lt;br&gt;
In this project, I automated the installation of &lt;strong&gt;Git&lt;/strong&gt; on a remote &lt;strong&gt;Managed Host&lt;/strong&gt; using an &lt;strong&gt;Ansible Playbook&lt;/strong&gt; executed from a &lt;strong&gt;Control Host&lt;/strong&gt;. The objective was to demonstrate real-world configuration management by securely provisioning software across systems using &lt;strong&gt;Ansible’s agentless architecture&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;After setting up &lt;strong&gt;passwordless sudo access&lt;/strong&gt; for the &lt;code&gt;ansible&lt;/code&gt; user on the managed host, I created a playbook (&lt;code&gt;install_git.yml&lt;/code&gt;) that uses the &lt;code&gt;apt&lt;/code&gt;module to install Git, ensuring the system cache is updated and the package is present.&lt;/p&gt;

&lt;p&gt;This project highlights core automation principles including:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Playbook creation&lt;/li&gt;
&lt;li&gt;Privilege escalation with &lt;code&gt;become: yes&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;Secure SSH-based remote execution&lt;/li&gt;
&lt;li&gt;Inventory group targeting with Ansible&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The successful execution of this playbook marks a key milestone in simplifying repeatable tasks in server administration — a foundational DevOps skill.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let's begin...&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Requirement:&lt;/strong&gt;&lt;br&gt;
Ensure you have enabled passwordless sudo on the managed-host.&lt;/p&gt;

&lt;p&gt;Run the command on the managed-host as the ansible user;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;su - ansible
sudo visudo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the command below at the end of the file.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ansible ALL=(ALL) NOPASSWD:ALL&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Save (CTRL+S) and exit (CTRL+X).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F724ohd1ntgcielngiwdi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F724ohd1ntgcielngiwdi.png" alt="Image description" width="800" height="611"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Creating the First Ansible Playbook&lt;/strong&gt;&lt;br&gt;
On the control-host, as the ansible user, create the playbook file:&lt;br&gt;
Run the command: &lt;code&gt;vi install_git.yml&lt;/code&gt;. An editor will open. Paste the following instructions into it. Remember to set paste (ESC KEY, then colon(:). type &lt;strong&gt;set paste&lt;/strong&gt; and enter) then right click to paste. You do set paste so your instructions are well aligned when you paste. Exit editor (esc:wq enter).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo4nszj9p5hxogdbqbhuz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo4nszj9p5hxogdbqbhuz.png" alt="Image description" width="649" height="245"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Run the command below to execute the Playbook:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ansible-playbook install_git.yml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7gkx8axg0r2w5b449mga.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7gkx8axg0r2w5b449mga.png" alt="Image description" width="800" height="203"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Verify Git Installation on Work-station&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once the playbook runs successfully, In the** control-host*&lt;em&gt;, **SSH&lt;/em&gt;* into the &lt;strong&gt;managed-host&lt;/strong&gt; and check Git version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh ansible@&amp;lt;managed-host ip&amp;gt;
git --version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see something like:&lt;br&gt;
&lt;code&gt;git version 2.43.0&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxxx33rgivnfw044ani74.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxxx33rgivnfw044ani74.png" alt="Image description" width="741" height="52"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Achievements: Installing Git Using Ansible Playbook&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Granted &lt;strong&gt;passwordless sudo access&lt;/strong&gt; to the ansible user on the &lt;strong&gt;Managed Host&lt;/strong&gt; via &lt;code&gt;visudo&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Created an &lt;strong&gt;Ansible playbook&lt;/strong&gt; (&lt;code&gt;install_git.yml&lt;/code&gt;) to automate Git installation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Defined the &lt;strong&gt;target host group (web)&lt;/strong&gt; in the playbook matching the inventory file.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Used&lt;code&gt;become: yes&lt;/code&gt; in the playbook to allow privilege escalation (sudo access).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Included an** apt module** task to:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Update the package cache&lt;/li&gt;
&lt;li&gt;Ensure Git is installed and up-to-date.

&lt;ol&gt;
&lt;li&gt;Executed the &lt;strong&gt;playbook&lt;/strong&gt; using the &lt;strong&gt;ansible-playbook command&lt;/strong&gt; from the &lt;strong&gt;Control Host&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Successfully connected to the &lt;strong&gt;Managed Host&lt;/strong&gt; over &lt;code&gt;SSH&lt;/code&gt; using the &lt;strong&gt;ansible user&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Verified the Git installation&lt;/strong&gt; by running &lt;code&gt;git --version&lt;/code&gt; on the &lt;strong&gt;Managed Host&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>ansible</category>
      <category>linuxadmin</category>
      <category>playbook</category>
      <category>git</category>
    </item>
    <item>
      <title>How to Set Up Passwordless SSH from Control Host Managed Host</title>
      <dc:creator>Bala Audu Musa</dc:creator>
      <pubDate>Sun, 22 Jun 2025 17:25:41 +0000</pubDate>
      <link>https://dev.to/bala_audu_musa/how-to-set-up-passwordless-ssh-from-control-host-managed-host-5a2h</link>
      <guid>https://dev.to/bala_audu_musa/how-to-set-up-passwordless-ssh-from-control-host-managed-host-5a2h</guid>
      <description>&lt;p&gt;&lt;strong&gt;Objective:&lt;/strong&gt;&lt;br&gt;
Allow &lt;strong&gt;ansible@Control-Host&lt;/strong&gt; to connect to &lt;strong&gt;ansible@Work-station&lt;/strong&gt; without typing a password (using SSH keys).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setup Requirements&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Two EC2 instances:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Control Host:&lt;/strong&gt; This is where you’ll download and install Ansible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Work-station:&lt;/strong&gt; This is the machine you want to manage. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We Begin...&lt;/strong&gt;&lt;br&gt;
Spin two &lt;strong&gt;EC2 instances (virtual servers)&lt;/strong&gt;. This can be achieved either by terraform, Azure or AWS.** Using AWS*&lt;em&gt;; &lt;br&gt;
Log into the **AWS portal&lt;/em&gt;* and search &lt;strong&gt;EC2&lt;/strong&gt; in the all-purpose search bar. Click &lt;strong&gt;EC2&lt;/strong&gt; in the displayed search option. In the &lt;strong&gt;Launch a virtual server&lt;/strong&gt; window, click on &lt;strong&gt;Launch instance&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzybew61uxfrphjmff9n7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzybew61uxfrphjmff9n7.png" alt="Image description" width="800" height="250"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the &lt;strong&gt;Launch an instance&lt;/strong&gt; page, make the following adjustments:&lt;br&gt;
&lt;strong&gt;Name and tags (Name):&lt;/strong&gt; &lt;em&gt;Leave blank&lt;/em&gt;&lt;br&gt;
&lt;strong&gt;Number of instances&lt;/strong&gt;: 2, &lt;br&gt;
&lt;strong&gt;Application and OS Images (Amazon Machine Image)&lt;/strong&gt;: Select Ubuntu&lt;br&gt;
&lt;strong&gt;Instance type:&lt;/strong&gt; leave in default &lt;strong&gt;t3.micro Free tier eligible&lt;/strong&gt;. In some other &lt;strong&gt;availability zones&lt;/strong&gt;, it is the &lt;strong&gt;t2.micro&lt;/strong&gt;.&lt;br&gt;
&lt;strong&gt;Key pair (login)&lt;/strong&gt;: Click on &lt;strong&gt;Create new key pair&lt;/strong&gt; if you don't have any existing one.&lt;br&gt;
Give key pair a &lt;strong&gt;name&lt;/strong&gt; and click on &lt;strong&gt;Create a key pair&lt;/strong&gt;. Note the downloaded &lt;strong&gt;key pair&lt;/strong&gt; for later use in this project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw8rtyrx48969ddf0ki8c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw8rtyrx48969ddf0ki8c.png" alt="Image description" width="695" height="625"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Network settings:&lt;/strong&gt; &lt;em&gt;take the defaults&lt;/em&gt; and click on &lt;strong&gt;Launch instance.&lt;/strong&gt; Click on &lt;strong&gt;View all instances&lt;/strong&gt;. Click on the &lt;strong&gt;pencil&lt;/strong&gt; to edit the names of the &lt;strong&gt;instances&lt;/strong&gt;. The first should be &lt;strong&gt;Control host&lt;/strong&gt; and second &lt;strong&gt;Managed host&lt;/strong&gt; or &lt;strong&gt;Remote host&lt;/strong&gt; or &lt;strong&gt;Work station host&lt;/strong&gt;.&lt;br&gt;
.&lt;br&gt;
&lt;strong&gt;NB:&lt;/strong&gt; A &lt;strong&gt;vpc&lt;/strong&gt;, &lt;strong&gt;Subnet&lt;/strong&gt;, &lt;strong&gt;Firewall (security groups)&lt;/strong&gt;, which** Allow SSH traffic from Anywhere (0.0.0.0/0)** will be created.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftqu0dcf9ejledfiy6kdd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftqu0dcf9ejledfiy6kdd.png" alt="Image description" width="800" height="146"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Copy&lt;/strong&gt; the &lt;strong&gt;Managed host&lt;/strong&gt;'s &lt;strong&gt;Public IPv4 address&lt;/strong&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Connect the created &lt;strong&gt;servers&lt;/strong&gt; to the &lt;strong&gt;terminal&lt;/strong&gt;. &lt;strong&gt;GitBash&lt;/strong&gt; or &lt;strong&gt;PowerShell terminals&lt;/strong&gt; can be used. Using the &lt;strong&gt;PowerShell terminal&lt;/strong&gt;;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Open PowerShell and enter the following command.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;[ssh -i 'C:/Users/fresh/Downloads/musa_key.pem' ubuntu@16.171.135.131](url)&lt;/code&gt;and enter.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;'C:/Users/fresh/Downloads/musa_key.pem'&lt;/code&gt; is the earlier downloaded key pair path.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;16.171.135.131&lt;/code&gt; is the &lt;strong&gt;Public IP address&lt;/strong&gt; of the &lt;strong&gt;Managed host&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbm0njw5qykss6x1b5hm7.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbm0njw5qykss6x1b5hm7.PNG" alt="Image description" width="800" height="172"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When prompted &lt;strong&gt;Are you sure you want to continue connecting (yes/no/[fingerprint])?&lt;br&gt;
**. Type **yes&lt;/strong&gt; and enter. Managed host has been successfully connected to the terminal. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl62v6yzlcpjm2d4tcqdp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl62v6yzlcpjm2d4tcqdp.png" alt="Image description" width="692" height="630"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We do the same, for the Control host to be connected in a separate terminal. Don't forget to change the Public IP address to that of the Control host. You should get the below result when successful.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flt9xe5gs3i1q5bhh0eap.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flt9xe5gs3i1q5bhh0eap.png" alt="Image description" width="748" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Icing sugar!&lt;/strong&gt;&lt;br&gt;
I encountered challenges connecting with this command &lt;code&gt;[ssh -i "C:/Users/fresh/Downloads/musa_key.pem20%(1)" ubuntu@16.171.135.131](url)&lt;/code&gt;. I had to rename the &lt;strong&gt;key pair path&lt;/strong&gt; to &lt;code&gt;'C:/Users/fresh/Downloads/musa_key.pem'&lt;/code&gt; in &lt;strong&gt;single quotation mark&lt;/strong&gt; before it went through successfully.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Changing the servers' name from &lt;code&gt;ubuntu@&lt;/code&gt; to &lt;code&gt;Control host&lt;/code&gt; and &lt;code&gt;Managed host&lt;/code&gt;.&lt;/strong&gt;&lt;br&gt;
Enter the command: &lt;br&gt;
&lt;code&gt;sudo hostnamectl set-hostname control-host&lt;/code&gt; in the Control host terminal and &lt;code&gt;sudo hostnamectl set-hostname managed-host&lt;/code&gt; terminal. Enter the command &lt;code&gt;logout&lt;/code&gt; and enter. Re-type and re-enter the command `[ssh -i 'C:/Users/fresh/Downloads/musa_key.pem' &lt;a href="mailto:ubuntu@16.171.135.131"&gt;ubuntu@16.171.135.131&lt;/a&gt;] again for the server name to change. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;for the control-host:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F32vlzvtag2tnjmo395qd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F32vlzvtag2tnjmo395qd.png" alt="Image description" width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;for the managed-host:&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsa0sa0fx2lpjs1pfusip.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsa0sa0fx2lpjs1pfusip.png" alt="Image description" width="798" height="507"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Creating an ansible user&lt;/strong&gt;&lt;br&gt;
Run the command; &lt;code&gt;sudo useradd -m -s /bin/bash ansible&lt;/code&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Adding the user to sudo group and granting the user administrative privileges.
Run the command; &lt;code&gt;sudo usermod -aG sudo ansible&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;6. Creating a password for ansible user.&lt;/strong&gt;&lt;br&gt;
Run the command: &lt;code&gt;sudo passwd ansible&lt;/code&gt;. Enter a password. Note that it won't show. Re-enter the password again to confirm.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Switching to the ansible user on the The Control Host
Run the command: &lt;code&gt;sudo su - ansible&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnom9utwqey2fra5pyzyu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnom9utwqey2fra5pyzyu.png" alt="Image description" width="489" height="106"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Do same to the Managed Host&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmteb4kto4afwzh0w5hwl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmteb4kto4afwzh0w5hwl.png" alt="Image description" width="586" height="139"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install ansible only on the control host
Run the following command: &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;&lt;br&gt;
sudo apt update &amp;amp;&amp;amp; sudo apt upgrade -y&lt;br&gt;
sudo apt install -y software-properties-common&lt;br&gt;
sudo add-apt-repository --yes --update ppa:ansible/ansible&lt;br&gt;
sudo apt install -y ansible&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;br&gt;
Wait for it to update and install ansible. Then confirm successful installation by running the command;&lt;br&gt;
&lt;code&gt;ansible --version&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7pt5jkpfuvinaqd4aa1g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7pt5jkpfuvinaqd4aa1g.png" alt="Image description" width="800" height="125"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ansible has been successfully installed in the control host.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Generate an SSH Key Pair on Control Host
Run the command: &lt;code&gt;ssh-keygen -t rsa -b 4096&lt;/code&gt;. Press Enter to all the prompts.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Two files will be created by this command; &lt;br&gt;
i) &lt;strong&gt;~/.ssh/id_rsa&lt;/strong&gt; → your private key (keep safe!)&lt;br&gt;
ii)** ~/.ssh/id_rsa.pub** → your public key (this is what you’ll copy to Work-station)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvlxtxv9iw1jtjds1n9lz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvlxtxv9iw1jtjds1n9lz.png" alt="Image description" width="800" height="422"&gt;&lt;/a&gt;&lt;br&gt;
Keypair has been successfully created.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Creating &lt;code&gt;-ssh&lt;/code&gt; folder on Managed Host
Run the following commands:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;&lt;br&gt;
mkdir -p ~/.ssh&lt;br&gt;
chmod 700 ~/.ssh&lt;br&gt;
touch ~/.ssh/authorized_keys&lt;br&gt;
chmod 600 ~/.ssh/authorized_keys&lt;br&gt;
chown -R ansible:ansible ~/.ssh&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Command                 Purpose&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;mkdir -p ~/.ssh&lt;/code&gt;     Creates the &lt;code&gt;.ssh&lt;/code&gt; directory in the user's home folder. The &lt;code&gt;-p &lt;/code&gt;ensures no error if it exists.&lt;br&gt;
&lt;code&gt;chmod 700 ~/.ssh&lt;/code&gt; Sets permissions on &lt;code&gt;.ssh&lt;/code&gt; so only the owner can read, write, or execute.&lt;br&gt;
&lt;code&gt;touch ~/.ssh/authorized_keys&lt;/code&gt; Creates the &lt;code&gt;authorized_keys&lt;/code&gt; file if it doesn't already exist.&lt;br&gt;
&lt;code&gt;chmod 600 ~/.ssh/authorized_keys&lt;/code&gt; Restricts &lt;code&gt;authorized_keys&lt;/code&gt; so only the owner can read or write it (secure SSH key file).&lt;br&gt;
&lt;code&gt;chown -R ansible:ansible ~/.ssh&lt;/code&gt;  Changes the ownership of &lt;code&gt;.ssh&lt;/code&gt; and all its contents to user ansible and group ansible.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Generating Public key from the Control Host: Run the command; &lt;code&gt;cat ~/.ssh/id_rsa.pub&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
Copy the whole key.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a folder in Managed Host with the command: &lt;br&gt;
&lt;code&gt;vi ~/.ssh/authorized_keys&lt;/code&gt;. Paste the copied key into it and exit (escape:wq + enter)&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F12kyrmdjupfkp8m9uz76.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F12kyrmdjupfkp8m9uz76.png" alt="Image description" width="652" height="717"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Re-run the following commands to double check. If no error messages, everything is fine.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;chmod 700 ~/.ssh&lt;br&gt;
chmod 600 ~/.ssh/authorized_keys&lt;br&gt;
chown -R ansible:ansible ~/.ssh&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;15. Test Passwordless in the Control Host&lt;/strong&gt;&lt;br&gt;
Run the command: &lt;code&gt;ssh ansible@&amp;lt;managed-host private ip&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb2btzp50ytaf1aerajrz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb2btzp50ytaf1aerajrz.png" alt="Image description" width="800" height="721"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We have accessed our managed host from the control host.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;16. Creating an Ansible Inventory File&lt;/strong&gt;&lt;br&gt;
The Ansible inventory file is a &lt;strong&gt;core configuration file&lt;/strong&gt; that tells Ansible which** hosts (servers, devices, or VMs) &lt;strong&gt;to manage, and optionally&lt;/strong&gt; how to group and connect to them.**. &lt;/p&gt;

&lt;p&gt;Run the command &lt;code&gt;sudo vi /etc/ansible/hosts&lt;/code&gt;. Once the text editor opens you should see texts already in it. Enter &lt;br&gt;
&lt;code&gt;[web]&lt;br&gt;
16.171.200.117 ansible_user=ansible&lt;/code&gt;. &lt;code&gt;16.171.200.117&lt;/code&gt; is the &lt;strong&gt;Public IP **address of the managed-host. Press **escape key :wq and enter&lt;/strong&gt; to save and exit the editor.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;[web]&lt;/code&gt; is the group name (you can call it whatever you want)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ansible_user=ansible&lt;/code&gt; tells Ansible to SSH into that machine using the ansible user.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdj4lqtblnmvtgu2jtiqm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdj4lqtblnmvtgu2jtiqm.png" alt="Image description" width="715" height="795"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;17. Testing Ansible Connection&lt;/strong&gt;&lt;br&gt;
On Control-Host Run this command " &lt;code&gt;ansible all -m ping&lt;/code&gt; "&lt;/p&gt;

&lt;p&gt;We should get An Output with a success Message.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiaoywjcldtv3lfbucbv6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiaoywjcldtv3lfbucbv6.png" alt="Image description" width="800" height="159"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It Shows we have Successfully Created &lt;strong&gt;Ansible Inventory File&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>ansible</category>
      <category>controlhost</category>
      <category>managedhost</category>
      <category>aws</category>
    </item>
    <item>
      <title>Copy-Paste Not Working Between Windows and Ubuntu VirtualBox? Here's the Fix!"</title>
      <dc:creator>Bala Audu Musa</dc:creator>
      <pubDate>Thu, 15 May 2025 22:12:31 +0000</pubDate>
      <link>https://dev.to/bala_audu_musa/copy-paste-not-working-between-windows-and-ubuntu-virtualbox-heres-the-fix-pa3</link>
      <guid>https://dev.to/bala_audu_musa/copy-paste-not-working-between-windows-and-ubuntu-virtualbox-heres-the-fix-pa3</guid>
      <description>&lt;p&gt;&lt;strong&gt;📝 Introduction&lt;/strong&gt;&lt;br&gt;
One of the most common frustrations faced by users running Ubuntu Linux in VirtualBox on a Windows host is the inability to copy and paste text—especially command-line instructions—between the two systems. This issue becomes particularly inconvenient when you're trying to copy terminal commands, configuration snippets, or file paths from Windows into Ubuntu, only to find that the clipboard doesn't work as expected. Fortunately, VirtualBox offers a feature called &lt;strong&gt;Shared Clipboard&lt;/strong&gt;, which allows seamless copy-paste between the host and guest operating systems. However, this functionality is not enabled by default and requires proper configuration, including the installation of &lt;strong&gt;Guest Additions&lt;/strong&gt; in the Ubuntu virtual machine. This guide walks you through the steps to enable clipboard sharing and eliminate the hassle of manual retyping.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A. Start Ubuntu in VirtualBox&lt;/strong&gt;&lt;br&gt;
Log into your Ubuntu VM.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyu1sybwi8gocjl46liwh.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyu1sybwi8gocjl46liwh.PNG" alt="Image description" width="780" height="656"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;B. Click on &lt;strong&gt;Devices&lt;/strong&gt; then on &lt;strong&gt;Insert Guest Addition CD Image...&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fly7gfxvcw0pt562eibmp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fly7gfxvcw0pt562eibmp.png" alt="Image description" width="800" height="383"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;C. If prompted to run it, choose Run. You might need to enter your password.&lt;/p&gt;

&lt;p&gt;If not prompted:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Open Terminal and run: 
sudo mkdir /media/cdrom
sudo mount /dev/cdrom /media/cdrom
sudo /media/cdrom/VBoxLinuxAdditions.run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You might need to run them one after the other.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What does each command do?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;sudo mkdir /media/cdrom&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Creates a &lt;strong&gt;new directory&lt;/strong&gt; called &lt;code&gt;cdrom&lt;/code&gt; inside &lt;code&gt;/media.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo&lt;/code&gt; is used to run the command with &lt;strong&gt;superuser (administrator) privileges.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo mount /dev/cdrom /media/cdrom&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Mounts the CD/DVD device (&lt;code&gt;/dev/cdrom&lt;/code&gt;) to the &lt;code&gt;/media/cdrom directory&lt;/code&gt;, making its contents accessible from that location.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo /media/cdrom/VBoxLinuxAdditions.run&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Executes the &lt;strong&gt;VirtualBox Guest Additions installer&lt;/strong&gt; from the mounted CD.&lt;/li&gt;
&lt;li&gt;This typically improves integration between a &lt;strong&gt;VirtualBox guest OS and the host&lt;/strong&gt; (e.g., better graphics support, shared clipboard, etc.).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In summary, these commands mount the &lt;strong&gt;VirtualBox Guest Additions CD&lt;/strong&gt; and install the tools inside a &lt;strong&gt;Linux virtual machine&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C. Reboot Ubuntu VM&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;sudo reboot&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Furthermore, &lt;strong&gt;Enable Shared Clipboard in VirtualBox Settings.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;On the Virtualbox start up page, click on &lt;strong&gt;setting&lt;/strong&gt;, then &lt;strong&gt;Advanced&lt;/strong&gt; and under &lt;strong&gt;Shared Clipboard&lt;/strong&gt;, click on &lt;strong&gt;Bidirectional.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flj16l99q6ljsy5453415.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flj16l99q6ljsy5453415.png" alt="Image description" width="800" height="597"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(Optional) Set &lt;strong&gt;Drag and Drop to Bidirectional&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test Copy and Paste&lt;/strong&gt;&lt;br&gt;
After rebooting Ubuntu:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Try copying text from Windows and pasting into Ubuntu (e.g., in Terminal or a text editor).&lt;/li&gt;
&lt;li&gt;Also try copying from Ubuntu to Windows.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Copy from window;&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwiw0y98tvfblvocw04qh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwiw0y98tvfblvocw04qh.png" alt="Image description" width="800" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Paste in Linux terminal;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxhq46t01gp2jb5dlys26.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxhq46t01gp2jb5dlys26.png" alt="Image description" width="800" height="679"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>virtualbox</category>
      <category>ubuntu</category>
      <category>clipboardsharing</category>
      <category>windowstolinux</category>
    </item>
    <item>
      <title>Transitioning Terraform State File from Local to Remote Backend</title>
      <dc:creator>Bala Audu Musa</dc:creator>
      <pubDate>Fri, 09 May 2025 20:39:20 +0000</pubDate>
      <link>https://dev.to/bala_audu_musa/transitioning-terraform-state-file-from-local-to-remote-backend-3097</link>
      <guid>https://dev.to/bala_audu_musa/transitioning-terraform-state-file-from-local-to-remote-backend-3097</guid>
      <description>&lt;p&gt;&lt;strong&gt;DEFINITION&lt;/strong&gt;&lt;br&gt;
The &lt;strong&gt;&lt;code&gt;terraform.tfstate&lt;/code&gt;&lt;/strong&gt; file is a &lt;strong&gt;JSON file&lt;/strong&gt; that Terraform uses to track the current state of your infrastructure. It acts as a source of truth, allowing Terraform to understand what resources already exist so it can determine what changes are needed during operations like &lt;code&gt;terraform apply&lt;/code&gt;. It's essential for ensuring that Terraform doesn't duplicate or unintentionally alter infrastructure. Because it can include sensitive data, it should be stored securely and never edited manually.&lt;/p&gt;

&lt;p&gt;Migrating Terraform state from local to remote storage is a** critical step for improving collaboration, security, and reliability in infrastructure as code.**&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What does terraform.tfstate file contain?&lt;/strong&gt;&lt;br&gt;
The terraform.tfstate file is in JSON format and contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Resource names and types (e.g., aws_instance.web_server)&lt;/li&gt;
&lt;li&gt;Resource properties (e.g., IP addresses, IDs, configurations)&lt;/li&gt;
&lt;li&gt;Metadata, dependencies, and outputs&lt;/li&gt;
&lt;li&gt;Sometimes sensitive information like secrets or credentials (unless 
specifically filtered out)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;WHY MIGRATE?&lt;/strong&gt;&lt;br&gt;
Migrating the file to remote state makes Terraform safer, more scalable, and team-friendly. It's like moving your most important documents from a personal notebook to a secure, shared digital vault—so everyone can work together, safely and efficiently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let's begin...&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Go to the link [&lt;a href="https://app.terraform.io/public/signup/account" rel="noopener noreferrer"&gt;https://app.terraform.io/public/signup/account&lt;/a&gt;]. Create a terraform registry account. Input &lt;strong&gt;Username&lt;/strong&gt;, &lt;strong&gt;email&lt;/strong&gt;, &lt;strong&gt;password&lt;/strong&gt; and click on &lt;strong&gt;Create account&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fad55y6k337j2w44s51vh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fad55y6k337j2w44s51vh.png" alt="Image description" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will be prompted that &lt;strong&gt;Confirm your email address&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk5ft01ub3l4wg6m1vjh4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk5ft01ub3l4wg6m1vjh4.png" alt="Image description" width="800" height="311"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go to your email and click on the confirmation link. It will then redirect you back to the terraform page. Click on &lt;strong&gt;Create organization&lt;/strong&gt;. An organization in the Terraform Registry is a shared namespace used to manage and publish Terraform modules or providers collaboratively under a team or company's name.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feca17fxdse063u299qsq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feca17fxdse063u299qsq.png" alt="Image description" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Input your &lt;strong&gt;organization name&lt;/strong&gt; and click on &lt;strong&gt;Create organization&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzh16zgkqekudbgeok1p9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzh16zgkqekudbgeok1p9.png" alt="Image description" width="800" height="330"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You are now on the Create a** Workspace page**. Click on the CLI-driven Workflow. HCP Terraform organizes your infrastructure resources by workspaces. A workspace contains infrastructure resources, variables, state data, and run history.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp5xp8m52gwlqion61b5s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp5xp8m52gwlqion61b5s.png" alt="Image description" width="800" height="329"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Choose a particular Workflow?&lt;/strong&gt;&lt;br&gt;
The &lt;strong&gt;CLI-driven workflow&lt;/strong&gt; is ideal for users who prefer working directly from the terminal while still benefiting from Terraform Cloud’s features like** remote state storage*&lt;em&gt;, **locking&lt;/em&gt;&lt;em&gt;, and **logging&lt;/em&gt;&lt;em&gt;. Unlike the **Version Control (VCS)-driven workflow&lt;/em&gt;&lt;em&gt;, which automatically runs plans and applies on every Git push—great for teams using **GitOps&lt;/em&gt;&lt;em&gt;—the&lt;/em&gt;* CLI-driven method** gives you more control and flexibility without needing to change your development habits. The &lt;strong&gt;API-driven workflow&lt;/strong&gt; offers the highest level of automation and customization through scripts or integrations but requires more setup and technical effort. Overall, the &lt;strong&gt;CLI-driven workflow&lt;/strong&gt; strikes a balance between ease of use, control, and cloud-backed reliability, making it a strong choice for individuals or small teams.&lt;/p&gt;

&lt;p&gt;Give your &lt;strong&gt;Workspace&lt;/strong&gt; a &lt;strong&gt;name&lt;/strong&gt; and click on &lt;strong&gt;Create&lt;/strong&gt;.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F742v3mrma2z5x1jh0qc9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F742v3mrma2z5x1jh0qc9.png" alt="Image description" width="800" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on your &lt;strong&gt;account logo&lt;/strong&gt;. Then click on &lt;strong&gt;Account settings&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1j9sa1lv9zgl8qzn5929.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1j9sa1lv9zgl8qzn5929.png" alt="Image description" width="800" height="264"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on &lt;strong&gt;Tokens&lt;/strong&gt; to generate one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ozh7n541cef8yeqc09h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ozh7n541cef8yeqc09h.png" alt="Image description" width="800" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on &lt;strong&gt;Create an API token&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkjxvpexdl5612agm9thz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkjxvpexdl5612agm9thz.png" alt="Image description" width="800" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Give your token a &lt;strong&gt;Description&lt;/strong&gt; and click on &lt;strong&gt;Generate token&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8atn8z8kqd0l1x4dcjaj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8atn8z8kqd0l1x4dcjaj.png" alt="Image description" width="800" height="466"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Copy&lt;/strong&gt; the &lt;strong&gt;token&lt;/strong&gt; and navigate to your VS code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fop6w2brr01vw93b5e6em.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fop6w2brr01vw93b5e6em.png" alt="Image description" width="800" height="175"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Run the code &lt;code&gt;terraform login&lt;/code&gt;. Type yes to proceed. Just** right click** and p*&lt;em&gt;ress the enter key&lt;/em&gt;* when asked to provide the &lt;strong&gt;Token for app.terraform.io.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9lije71y8vkhjbkhfcoh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9lije71y8vkhjbkhfcoh.png" alt="Image description" width="800" height="582"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should get the picture below;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnarg03h0ttrk4xwhdd3z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnarg03h0ttrk4xwhdd3z.png" alt="Image description" width="800" height="402"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Navigate back to Terraform cloud to copy your code. To locate the code. Click on &lt;strong&gt;Choose an organization&lt;/strong&gt; at the bottom left hand corner of the page. Then click on your &lt;strong&gt;organization name&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F93o45up694e94rwykiq0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F93o45up694e94rwykiq0.png" alt="Image description" width="800" height="403"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on your &lt;strong&gt;Workspace name&lt;/strong&gt;. In this case &lt;strong&gt;Musa-workspace&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fflt6ogzruxiavwpsslmw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fflt6ogzruxiavwpsslmw.png" alt="Image description" width="800" height="302"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Boom there is your &lt;strong&gt;configuration code block&lt;/strong&gt;. Copy the segment of it highlighted below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9mmbketu6qf1mflibiri.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9mmbketu6qf1mflibiri.png" alt="Image description" width="800" height="489"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We now need to add the code block to our &lt;strong&gt;Terraform configuration files&lt;/strong&gt; to set up the &lt;strong&gt;cloud integration&lt;/strong&gt;. Navigate to VS code, click on &lt;strong&gt;&lt;code&gt;main.tf&lt;/code&gt;file&lt;/strong&gt; and paste the copied code block between line 7 and 9 (i.e line 8) and &lt;strong&gt;CTRL S **to **save&lt;/strong&gt;. You should have something like the one below;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feouhoyw9v21vdyauccz7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feouhoyw9v21vdyauccz7.png" alt="Image description" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Navigate to VS code and run &lt;code&gt;terraform login&lt;/code&gt; again. Click on generate a new token. Copy it and proceed to right click in the VS code. You should get the result below once again.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbftf9wwnp6w12wcxpk3q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbftf9wwnp6w12wcxpk3q.png" alt="Image description" width="800" height="345"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Navigate to terraform cloud and click on State. It can be seen no saved states yet.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnlhjeg9e8twucpxv6ps2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnlhjeg9e8twucpxv6ps2.png" alt="Image description" width="800" height="324"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Navigate to VS code and Run &lt;code&gt;terraform init&lt;/code&gt;. Afterwards check state in terraform cloud. You should now see it in shaa Allah.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuaxaht9yjecheiuulfi0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuaxaht9yjecheiuulfi0.png" alt="Image description" width="800" height="291"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From the foregoing we have successfully migrated &lt;strong&gt;terraform.tfstate&lt;/strong&gt; file to terraform cloud (Remote setting).&lt;/p&gt;

&lt;p&gt;We can decide to delete it from our local state with the command &lt;code&gt;**rm terraform.tfstate**&lt;/code&gt;. Since we already have it in the remote state.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bonus&lt;/strong&gt;&lt;br&gt;
If you already had existing resources, you can run the command &lt;strong&gt;&lt;code&gt;terraform import azurerm_resource_group.test 'full resource id'&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To get the full resource id;&lt;br&gt;
Navigate to Azure (in this case), Resource group then settings. Click on Properties and copy the resource id. &lt;/p&gt;

&lt;p&gt;in VS code run the command above. Thereafter run &lt;code&gt;terraform init&lt;/code&gt;and yes when appropriate. Visit &lt;strong&gt;terraform cloud&lt;/strong&gt; to find your &lt;strong&gt;State&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;List of Achievements&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Created a Terraform Cloud account&lt;/strong&gt; via the official signup portal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verified the email address&lt;/strong&gt; to activate the Terraform Cloud account.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Created a new organization&lt;/strong&gt; in Terraform Cloud to group and manage infrastructure projects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Created a workspace&lt;/strong&gt; using the** CLI-driven workflow**, ideal for terminal-based operations.&lt;/li&gt;
&lt;li&gt;**Generated an API token **for secure authentication between Terraform CLI and Terraform Cloud.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logged in to Terraform Cloud&lt;/strong&gt; from the terminal using &lt;code&gt;terraform login&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Copied and added the &lt;strong&gt;remote backend configuration block&lt;/strong&gt; into the local &lt;code&gt;main.tf&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;Ran &lt;code&gt;terraform init&lt;/code&gt; to reinitialize the project and migrate the state to the remote backend.&lt;/li&gt;
&lt;li&gt;Confirmed successful state migration by verifying the uploaded state in Terraform Cloud.&lt;/li&gt;
&lt;li&gt;Optionally deleted the local &lt;code&gt;terraform.tfstate&lt;/code&gt; file to avoid duplication and conflicts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;(Bonus)&lt;/strong&gt; Demonstrated how to import existing Azure resources into Terraform using terraform import.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>terraformcloud</category>
      <category>statemigration</category>
      <category>infrastructureascode</category>
      <category>clidrivenworkflow</category>
    </item>
    <item>
      <title>Hands-On Guide to Azure Infrastructure as Code Using Terraform and GitHub</title>
      <dc:creator>Bala Audu Musa</dc:creator>
      <pubDate>Fri, 09 May 2025 14:42:05 +0000</pubDate>
      <link>https://dev.to/bala_audu_musa/hands-on-guide-to-azure-infrastructure-as-code-using-terraform-and-github-5ak3</link>
      <guid>https://dev.to/bala_audu_musa/hands-on-guide-to-azure-infrastructure-as-code-using-terraform-and-github-5ak3</guid>
      <description>&lt;p&gt;Have you wondered how you could build resources in the cloud without the normal clickings? For example: &lt;/p&gt;

&lt;p&gt;You write down (in code):&lt;br&gt;
"&lt;em&gt;I want a resource group in Azure, name it &lt;strong&gt;test-group&lt;/strong&gt; and put it in &lt;strong&gt;East US&lt;/strong&gt;.&lt;/em&gt;"&lt;/p&gt;

&lt;p&gt;That is what exactly &lt;strong&gt;Terraform&lt;/strong&gt; does. How does it do this?&lt;/p&gt;

&lt;p&gt;Terraform reads that note.&lt;/p&gt;

&lt;p&gt;It &lt;strong&gt;logs&lt;/strong&gt; into &lt;strong&gt;Azure **or any other cloud providers and **builds exactly what you asked for&lt;/strong&gt;, all from the code terminal — no clicks needed. &lt;/p&gt;

&lt;p&gt;You then login to your cloud provider portal to check and boom - there is everything, already created for you. Sounds cool right? &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terraform is like a recipe book for building things in the cloud.&lt;/strong&gt;&lt;br&gt;
Just like how:&lt;/p&gt;

&lt;p&gt;A recipe tells your kitchen what ingredients to use and how to cook,&lt;/p&gt;

&lt;p&gt;Terraform code tells Azure (or any cloud) what to build — like a virtual machine, database, or storage.&lt;/p&gt;

&lt;p&gt;Terraform is an &lt;strong&gt;infrastructure-as-code (IAC)&lt;/strong&gt; software tool created by HashiCorp. The user tells Terraform what cloud resources to build, and Terraform builds them.&lt;/p&gt;




&lt;p&gt;After understanding completely what terraform is all about, let us understand some basic terraform commands.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Commands in Terraform.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;terraform init&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;"Get ready!"&lt;/em&gt; – Sets things up and downloads what Terraform needs.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;terraform plan&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;"What will happen?"&lt;/em&gt; – Shows what it would build or change. &lt;/p&gt;

&lt;p&gt;`&lt;code&gt;terraform apply&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;"Go!"&lt;/em&gt; – Actually builds the stuff in the cloud.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;terraform destroy&lt;/code&gt; &lt;br&gt;
&lt;em&gt;"Clean up!"&lt;/em&gt; – Destroys everything you made.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;terraform fmt&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;"Make it neat!"&lt;/em&gt; – Fixes spacing and formatting in our files.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;terraform validate&lt;/code&gt; &lt;br&gt;
&lt;em&gt;"Is this okay?"&lt;/em&gt; – Checks if your code has mistakes.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;terraform show&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;"What did I build?"&lt;/em&gt; – Shows details of what exists now.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;terraform output&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;"Give me the results."&lt;/em&gt; – Shows final values after building stuff.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;terraform version&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;"What version is this?"&lt;/em&gt;– Tells you the Terraform version.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Setting Up Terraform on Windows&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There are two ways this can be done;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Manual Download of terraform and adding its path to environment 
variable on Windows.&lt;/li&gt;
&lt;li&gt;Running the command; &lt;code&gt;choco install terraform&lt;/code&gt; in &lt;strong&gt;Windows 
PowerShell&lt;/strong&gt;.
---&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;A. Manual Installation&lt;/strong&gt;&lt;br&gt;
i. Go to [&lt;a href="https://developer.hashicorp.com/terraform" rel="noopener noreferrer"&gt;https://developer.hashicorp.com/terraform&lt;/a&gt;] and click on &lt;strong&gt;Install.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd98segxpxjdb0i4dub1w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd98segxpxjdb0i4dub1w.png" alt="Image description" width="800" height="325"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ii. Select your operating system and your processor architecture. In this case &lt;strong&gt;Windows&lt;/strong&gt; was selected and the &lt;strong&gt;download **in front of **amd64&lt;/strong&gt; was clicked to download the terraform file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Brief Expo&lt;/strong&gt;&lt;br&gt;
The choice between &lt;code&gt;386&lt;/code&gt; and &lt;code&gt;AMD64&lt;/code&gt; when downloading Terraform (or any software) depends on your &lt;strong&gt;computer's CPU architecture&lt;/strong&gt; — specifically whether it's a 32-bit or 64-bit system.&lt;/p&gt;

&lt;p&gt;Use &lt;strong&gt;&lt;code&gt;386&lt;/code&gt;&lt;/strong&gt; if your PC is very old or 32-bit, and &lt;strong&gt;&lt;code&gt;AMD64&lt;/code&gt;&lt;/strong&gt; if your PC is modern and 64-bit (which is most systems today).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IN SIMPLE TERMS&lt;/strong&gt;&lt;br&gt;
If your computer is newer than &lt;strong&gt;2010&lt;/strong&gt;, you almost definitely need &lt;code&gt;amd64&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Continuation...&lt;/strong&gt;&lt;br&gt;
When the folder has downloaded, a pop-up will be seen has shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg8ns2nllqk3t5nfv4jj6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg8ns2nllqk3t5nfv4jj6.png" alt="Image description" width="593" height="230"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Double click on the pop-up or go to &lt;strong&gt;file manager&lt;/strong&gt; and click on &lt;strong&gt;Downloads&lt;/strong&gt; to reveal it. It will be noted that it is a &lt;strong&gt;zip folder&lt;/strong&gt;. &lt;strong&gt;Right click&lt;/strong&gt; and click on &lt;strong&gt;Extract all&lt;/strong&gt; to have access to its contents.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff05wvhu45ea591x5mi6h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff05wvhu45ea591x5mi6h.png" alt="Image description" width="800" height="239"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on &lt;strong&gt;Extract&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqgie3x8sd99jweprm2gp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqgie3x8sd99jweprm2gp.png" alt="Image description" width="468" height="346"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once extraction is done. Right click on the** terraform file** and &lt;strong&gt;copy the path&lt;/strong&gt;. But for the system we are using the option to copy path is absent. Hence, we must setup terraform using the &lt;strong&gt;second method&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fljtogje5oz5wlh4a7wit.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fljtogje5oz5wlh4a7wit.png" alt="Image description" width="800" height="323"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But for those whose system has the option, I will go on and explain how they can get it done.&lt;/p&gt;

&lt;p&gt;Navigate to the &lt;strong&gt;Windows start menu&lt;/strong&gt; and search for &lt;strong&gt;Environment variables&lt;/strong&gt;. Click on &lt;strong&gt;Edit the system environment variables.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4rnk8ixays3jamerwt6h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4rnk8ixays3jamerwt6h.png" alt="Image description" width="749" height="541"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;System properties&lt;/strong&gt; dialog box will open up. Under &lt;strong&gt;Advanced option&lt;/strong&gt; click on &lt;strong&gt;Environment variables..&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmxq4ay0st170s4fnt1go.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmxq4ay0st170s4fnt1go.png" alt="Image description" width="347" height="359"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Under &lt;strong&gt;System variables&lt;/strong&gt; select &lt;strong&gt;Path&lt;/strong&gt; and click on &lt;strong&gt;Edit...&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7j8hxhbf09fxxy47n10j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7j8hxhbf09fxxy47n10j.png" alt="Image description" width="466" height="439"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Click on &lt;strong&gt;New...&lt;/strong&gt; and paste the &lt;strong&gt;terraform path&lt;/strong&gt; you had copied while ensuring it is without quotation marks. &lt;strong&gt;Ok ** every opened **dialog box&lt;/strong&gt; and proceed to sign-in to &lt;strong&gt;GitHub account&lt;/strong&gt; to create a &lt;strong&gt;repository&lt;/strong&gt;.
&lt;/h2&gt;

&lt;p&gt;Before proceeding to GitHub, let's recall that we weren't able to setup terraform with the first method. Now let's use the second method.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;B. Running the command; &lt;code&gt;choco install terraform&lt;/code&gt; in **Windows &lt;br&gt;
   PowerShell&lt;/strong&gt;.**&lt;/p&gt;

&lt;p&gt;Navigate to the Windows start up menu search bar and type in &lt;strong&gt;PowerShell&lt;/strong&gt; and click on &lt;strong&gt;Run as administrator&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbb30dro5rl7joz7oevmt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbb30dro5rl7joz7oevmt.png" alt="Image description" width="800" height="620"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before you run &lt;code&gt;choco install terraform&lt;/code&gt;, here are the &lt;strong&gt;prerequisites&lt;/strong&gt; in very &lt;strong&gt;simple terms&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;i. &lt;strong&gt;Windows OS&lt;/strong&gt;: You're using a Windows computer (Chocolatey is for&lt;br&gt;
   Windows).&lt;/p&gt;

&lt;p&gt;ii. &lt;strong&gt;Admin Access:&lt;/strong&gt; You must run PowerShell or Command Prompt as&lt;br&gt;
    Administrator.&lt;/p&gt;

&lt;p&gt;iii. **Chocolatey Installed: **You need to have Chocolatey installed &lt;br&gt;
     first. &lt;/p&gt;

&lt;p&gt;Run the command: &lt;code&gt;choco install terraform.&lt;/code&gt; When prompted &lt;strong&gt;if you want to run the Script?&lt;/strong&gt;, type &lt;strong&gt;'A'&lt;/strong&gt; to answer &lt;strong&gt;yes to all&lt;/strong&gt; and press the &lt;strong&gt;Enter key&lt;/strong&gt;. You should get the result below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw8mgw963jxsgphb6osps.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw8mgw963jxsgphb6osps.png" alt="Image description" width="800" height="488"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To further confirm if successfully installed, run the command &lt;code&gt;terraform --version&lt;/code&gt;. You should get something like &lt;code&gt;Terraform v1.11.4&lt;/code&gt;. Thus indicating successful installation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj27aofw4kznuqltp5psy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj27aofw4kznuqltp5psy.png" alt="Image description" width="800" height="137"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PREPARATION OF GITHUB TO COMMUNICATE WITH VS CODE&lt;/strong&gt;&lt;br&gt;
in GitHub, click on the drop-down arrow, then click on &lt;strong&gt;New repository&lt;/strong&gt; to create one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frcbtulmqsyz8s0qpgb0q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frcbtulmqsyz8s0qpgb0q.png" alt="Image description" width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Give the &lt;strong&gt;repository&lt;/strong&gt; a name, in this case &lt;strong&gt;Repo1&lt;/strong&gt; and click the box of &lt;strong&gt;Add a README file&lt;/strong&gt; to tick it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftma15fcuto47tde63ga4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftma15fcuto47tde63ga4.png" alt="Image description" width="800" height="385"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on &lt;strong&gt;Create repository&lt;/strong&gt; to create the repository.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm7ogm51jkve4ojt51qyi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm7ogm51jkve4ojt51qyi.png" alt="Image description" width="800" height="266"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on &lt;strong&gt;Code **and click on the highlight **copy symbol&lt;/strong&gt; to copy the &lt;strong&gt;HTTP URL&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjc1qhgyw2tbo0ifknfn0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjc1qhgyw2tbo0ifknfn0.png" alt="Image description" width="800" height="357"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NUGGET;&lt;/strong&gt;&lt;br&gt;
We use the &lt;strong&gt;HTTP URL&lt;/strong&gt; to clone with Visual Studio (VS) because it works without extra setup, while &lt;strong&gt;SSH&lt;/strong&gt; and &lt;strong&gt;GitHub CLI&lt;/strong&gt; need extra configuration or tools installed.&lt;/p&gt;

&lt;p&gt;We now need to clone the created repository in VS code.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;CLONING A GITHUB REPOSITORY IN VS CODE&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Open VS code and begin by installing the &lt;strong&gt;terraform extension&lt;/strong&gt;. Click on the extensions icon on the left, then in the search bar type &lt;strong&gt;terraform&lt;/strong&gt; and install the &lt;strong&gt;HashiCorp terraform&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwi2t5rkpgc4f75bccp76.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwi2t5rkpgc4f75bccp76.png" alt="Image description" width="796" height="325"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once it has finished installing, you should see the &lt;strong&gt;terraform extension icons&lt;/strong&gt; to the left as hightlighted below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs48rmgx0nre97oio46ux.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs48rmgx0nre97oio46ux.png" alt="Image description" width="800" height="353"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TO CLONE...&lt;/strong&gt;&lt;br&gt;
Navigate to the &lt;strong&gt;Source control icon&lt;/strong&gt; on the left and click. Then click on the &lt;strong&gt;Clone repository&lt;/strong&gt; option. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fopoutfz0g3j60lvacqw0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fopoutfz0g3j60lvacqw0.png" alt="Image description" width="287" height="283"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the &lt;strong&gt;Clone from GitHub&lt;/strong&gt; option.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhdq3xlamofplcwgwwix5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhdq3xlamofplcwgwwix5.png" alt="Image description" width="800" height="207"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on your created repository name in GitHub among the listed options.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxe3utx002owre15j0eq2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxe3utx002owre15j0eq2.png" alt="Image description" width="800" height="192"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Right click in the open dialog box. Then click on &lt;strong&gt;New&lt;/strong&gt; and then &lt;strong&gt;Folder&lt;/strong&gt; to create a folder for your repository.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frqibqq3odooh1396pgaq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frqibqq3odooh1396pgaq.png" alt="Image description" width="707" height="464"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Give your folder a name, press the Enter key and click on &lt;strong&gt;Select as repository destination&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5biv2r66ilft9sqy1kyg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5biv2r66ilft9sqy1kyg.png" alt="Image description" width="512" height="365"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on** Open** in the pop-up dialog box.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fch1efluvg9l0a4dd8l66.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fch1efluvg9l0a4dd8l66.png" alt="Image description" width="531" height="224"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The repository has successfully been cloned into VS code has highlighted below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy0tu0buovkyta9csuhp0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy0tu0buovkyta9csuhp0.png" alt="Image description" width="800" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CREATING A &lt;code&gt;main.tf&lt;/code&gt; file.&lt;/strong&gt;&lt;br&gt;
A main.tf file is like the &lt;strong&gt;main recipe&lt;/strong&gt; in Terraform — it tells Terraform **what to build **in the cloud, like virtual machines or networks.&lt;/p&gt;

&lt;p&gt;Simple Example:&lt;br&gt;
If Terraform is a cook, &lt;code&gt;main.tf&lt;/code&gt; is the instruction sheet saying:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Make 2 pizzas (VMs), 1 drink (storage), and serve it on a tray (network)."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Without &lt;strong&gt;main.tf&lt;/strong&gt;, Terraform wouldn’t know what you want it to create. Hence this must be kept safe.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To continue...&lt;/strong&gt;&lt;br&gt;
Click on the &lt;strong&gt;file icon&lt;/strong&gt; in front of the &lt;strong&gt;repository name&lt;/strong&gt;. Type into the empty bar &lt;code&gt;main.tf&lt;/code&gt;and press the &lt;strong&gt;Enter button&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftc90h38qk2gsholneyu6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftc90h38qk2gsholneyu6.png" alt="Image description" width="800" height="289"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;main.tf&lt;/code&gt; file has just been created.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftps9niv5s9i3el6rg3bu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftps9niv5s9i3el6rg3bu.png" alt="Image description" width="764" height="249"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From the foregoing, the field has been prepared for us to begin planting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CONNECTING TERRAFORM TO CLOUD SERVICE PROVIDER (AZURE)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We connect Terraform to a &lt;strong&gt;cloud service provider **like **Azure&lt;/strong&gt; so it can &lt;strong&gt;create and manage&lt;/strong&gt; real cloud resources for us automatically, like &lt;strong&gt;virtual machines&lt;/strong&gt;, &lt;strong&gt;storage accounts&lt;/strong&gt;, or &lt;strong&gt;networks&lt;/strong&gt; — instead of us &lt;strong&gt;clicking around manually&lt;/strong&gt; in the &lt;strong&gt;Azure Portal&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layman Analogy:&lt;/strong&gt;&lt;br&gt;
Imagine** Terraform &lt;strong&gt;is a **remote control&lt;/strong&gt;, and &lt;strong&gt;Azure&lt;/strong&gt; is your &lt;strong&gt;smart TV&lt;/strong&gt;.&lt;br&gt;
To change the &lt;strong&gt;channel&lt;/strong&gt; (&lt;strong&gt;make cloud changes&lt;/strong&gt;), Terraform needs to connect to the &lt;strong&gt;TV&lt;/strong&gt; (&lt;strong&gt;Azure&lt;/strong&gt;) — otherwise, the remote won’t do anything.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What do Providers do?&lt;/strong&gt;&lt;br&gt;
A &lt;strong&gt;provider&lt;/strong&gt; is a &lt;strong&gt;plugin&lt;/strong&gt; that allows &lt;strong&gt;Terraform&lt;/strong&gt; to interact with &lt;strong&gt;external systems&lt;/strong&gt; — like &lt;strong&gt;cloud platforms&lt;/strong&gt; (e.g., &lt;strong&gt;AWS&lt;/strong&gt;, &lt;strong&gt;Azure&lt;/strong&gt;, &lt;strong&gt;Google Cloud&lt;/strong&gt;), &lt;strong&gt;SaaS services&lt;/strong&gt; (e.g., &lt;strong&gt;GitHub&lt;/strong&gt;, &lt;strong&gt;Cloudflare&lt;/strong&gt;), or even &lt;strong&gt;local systems&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Go to [&lt;a href="https://registry.terraform.io/browse/providers" rel="noopener noreferrer"&gt;https://registry.terraform.io/browse/providers&lt;/a&gt;] and among the various &lt;strong&gt;providers&lt;/strong&gt;, click on &lt;strong&gt;Azure&lt;/strong&gt; as we intend using &lt;strong&gt;Azure Cloud&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvy14lsrwnk7j3p9yeg2e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvy14lsrwnk7j3p9yeg2e.png" alt="Image description" width="800" height="402"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on &lt;strong&gt;USE PROVIDER&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5i6ukhqnbgifrpqwfh1o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5i6ukhqnbgifrpqwfh1o.png" alt="Image description" width="800" height="377"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Copy the &lt;strong&gt;code&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdqm41gdglgavvah4fvay.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdqm41gdglgavvah4fvay.png" alt="Image description" width="445" height="650"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Paste&lt;/strong&gt; the code into the &lt;code&gt;main.tf&lt;/code&gt; file created in &lt;strong&gt;VS code&lt;/strong&gt;. Make the following adjustments into the code&lt;br&gt;
&lt;strong&gt;In line 11:&lt;/strong&gt; Delete the comment &lt;code&gt;# Configuration options&lt;/code&gt; and replace with &lt;code&gt;features {&lt;/code&gt;. Note that as you type &lt;strong&gt;features&lt;/strong&gt;, the &lt;strong&gt;features plugin&lt;/strong&gt; starting prompting, just &lt;strong&gt;select it&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Move the curly brace in &lt;strong&gt;Line 13 to 14&lt;/strong&gt; and type in its stead &lt;code&gt;subscription id&lt;/code&gt;. Select it when prompted and input your Azure &lt;strong&gt;subscription id&lt;/strong&gt; copied from your Azure account. Ensure that your subscription id is within &lt;strong&gt;quotation marks&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwykdrgvkbnly4dc737ub.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwykdrgvkbnly4dc737ub.png" alt="Image description" width="800" height="241"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the &lt;strong&gt;three dots(...)&lt;/strong&gt; in front of &lt;strong&gt;Run&lt;/strong&gt; in the &lt;strong&gt;VS code&lt;/strong&gt; interface. Then click on &lt;strong&gt;Terminal&lt;/strong&gt;. Then click on &lt;strong&gt;New terminal&lt;/strong&gt; to start running the &lt;strong&gt;Terraform commands.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc8z7vrixjn5fhceezwlo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc8z7vrixjn5fhceezwlo.png" alt="Image description" width="800" height="204"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;THE **&lt;code&gt;terraform init&lt;/code&gt;&lt;/strong&gt; Command**&lt;br&gt;
&lt;code&gt;terraform init&lt;/code&gt;prepares your project to use Terraform by downloading the necessary provider &lt;strong&gt;plugins&lt;/strong&gt; (like AWS, Azure, etc.). It sets up your &lt;strong&gt;working directory&lt;/strong&gt; and &lt;strong&gt;configures backend settings&lt;/strong&gt; if needed. It also &lt;strong&gt;locks provider versions&lt;/strong&gt; to ensure consistency in future runs. This information is stored in a file called &lt;code&gt;**.terraform.lock.hcl.**&lt;/code&gt;as can be seen below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3xkyp5zqsa3yb5xwk832.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3xkyp5zqsa3yb5xwk832.png" alt="Image description" width="800" height="504"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CREATING RESOURCES IN AZURE WITH TERRAFORM&lt;/strong&gt;&lt;br&gt;
Ask any of the AI chatbots or large language model (LLM) assistants like ChatGPT, DeepSeek etc to write you any terraform code for anything you want to create. We will be using the following code as an example.&lt;br&gt;
`&lt;br&gt;
terraform {&lt;br&gt;
  required_providers {&lt;br&gt;
    azurerm = {&lt;br&gt;
      source = "hashicorp/azurerm"&lt;br&gt;
      version = "4.27.0"&lt;br&gt;
    }&lt;br&gt;
  }&lt;br&gt;
}&lt;br&gt;
provider "azurerm" {&lt;br&gt;
    features {}&lt;br&gt;
subscription_id = "5fdd1cff-4911-4d4a-b28a-969756021e0f"&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;resource "azurerm_resource_group" "test" {&lt;br&gt;
   name     = "acctestrg"&lt;br&gt;
   location = "West US 2"&lt;br&gt;
 }&lt;/p&gt;

&lt;p&gt;resource "azurerm_virtual_network" "test" {&lt;br&gt;
   name                = "acctvn"&lt;br&gt;
   address_space       = ["10.0.0.0/16"]&lt;br&gt;
   location            = azurerm_resource_group.test.location&lt;br&gt;
   resource_group_name = azurerm_resource_group.test.name&lt;br&gt;
 }&lt;/p&gt;

&lt;p&gt;resource "azurerm_subnet" "test" {&lt;br&gt;
   name                 = "acctsub"&lt;br&gt;
   resource_group_name  = azurerm_resource_group.test.name&lt;br&gt;
   virtual_network_name = azurerm_virtual_network.test.name&lt;br&gt;
   address_prefixes     = ["10.0.2.0/24"]&lt;br&gt;
 }&lt;/p&gt;

&lt;p&gt;resource "azurerm_public_ip" "test" {&lt;br&gt;
   name                         = "publicIPForLB"&lt;br&gt;
   location                     = azurerm_resource_group.test.location&lt;br&gt;
   resource_group_name          = azurerm_resource_group.test.name&lt;br&gt;
   allocation_method            = "Static"&lt;br&gt;
 }&lt;/p&gt;

&lt;p&gt;resource "azurerm_lb" "test" {&lt;br&gt;
   name                = "loadBalancer"&lt;br&gt;
   location            = azurerm_resource_group.test.location&lt;br&gt;
   resource_group_name = azurerm_resource_group.test.name&lt;/p&gt;

&lt;p&gt;frontend_ip_configuration {&lt;br&gt;
     name                 = "publicIPAddress"&lt;br&gt;
     public_ip_address_id = azurerm_public_ip.test.id&lt;br&gt;
   }&lt;br&gt;
 }&lt;/p&gt;

&lt;p&gt;resource "azurerm_lb_backend_address_pool" "test" {&lt;br&gt;
   loadbalancer_id     = azurerm_lb.test.id&lt;br&gt;
   name                = "BackEndAddressPool"&lt;br&gt;
 }&lt;/p&gt;

&lt;p&gt;resource "azurerm_network_interface" "test" {&lt;br&gt;
   count               = 2&lt;br&gt;
   name                = "acctni${count.index}"&lt;br&gt;
   location            = azurerm_resource_group.test.location&lt;br&gt;
   resource_group_name = azurerm_resource_group.test.name&lt;/p&gt;

&lt;p&gt;ip_configuration {&lt;br&gt;
     name                          = "testConfiguration"&lt;br&gt;
     subnet_id                     = azurerm_subnet.test.id&lt;br&gt;
     private_ip_address_allocation = "Dynamic"&lt;br&gt;
   }&lt;br&gt;
 }&lt;/p&gt;

&lt;p&gt;resource "azurerm_managed_disk" "test" {&lt;br&gt;
   count                = 2&lt;br&gt;
   name                 = "datadisk_existing_${count.index}"&lt;br&gt;
   location             = azurerm_resource_group.test.location&lt;br&gt;
   resource_group_name  = azurerm_resource_group.test.name&lt;br&gt;
   storage_account_type = "Standard_LRS"&lt;br&gt;
   create_option        = "Empty"&lt;br&gt;
   disk_size_gb         = "1023"&lt;br&gt;
 }&lt;/p&gt;

&lt;p&gt;resource "azurerm_availability_set" "avset" {&lt;br&gt;
   name                         = "avset"&lt;br&gt;
   location                     = azurerm_resource_group.test.location&lt;br&gt;
   resource_group_name          = azurerm_resource_group.test.name&lt;br&gt;
   platform_fault_domain_count  = 2&lt;br&gt;
   platform_update_domain_count = 2&lt;br&gt;
   managed                      = true&lt;br&gt;
 }&lt;/p&gt;

&lt;p&gt;resource "azurerm_virtual_machine" "test" {&lt;br&gt;
   count                 = 2&lt;br&gt;
   name                  = "acctvm${count.index}"&lt;br&gt;
   location              = azurerm_resource_group.test.location&lt;br&gt;
   availability_set_id   = azurerm_availability_set.avset.id&lt;br&gt;
   resource_group_name   = azurerm_resource_group.test.name&lt;br&gt;
   network_interface_ids = [element(azurerm_network_interface.test.*.id, count.index)]&lt;br&gt;
   vm_size               = "Standard_DS1_v2"&lt;/p&gt;

&lt;p&gt;# Uncomment this line to delete the OS disk automatically when deleting the VM&lt;br&gt;
   # delete_os_disk_on_termination = true&lt;/p&gt;

&lt;p&gt;# Uncomment this line to delete the data disks automatically when deleting the VM&lt;br&gt;
   # delete_data_disks_on_termination = true&lt;/p&gt;

&lt;p&gt;storage_image_reference {&lt;br&gt;
     publisher = "Canonical"&lt;br&gt;
     offer     = "UbuntuServer"&lt;br&gt;
     sku       = "16.04-LTS"&lt;br&gt;
     version   = "latest"&lt;br&gt;
   }&lt;/p&gt;

&lt;p&gt;storage_os_disk {&lt;br&gt;
     name              = "myosdisk${count.index}"&lt;br&gt;
     caching           = "ReadWrite"&lt;br&gt;
     create_option     = "FromImage"&lt;br&gt;
     managed_disk_type = "Standard_LRS"&lt;br&gt;
   }&lt;/p&gt;

&lt;p&gt;# Optional data disks&lt;br&gt;
   storage_data_disk {&lt;br&gt;
     name              = "datadisk_new_${count.index}"&lt;br&gt;
     managed_disk_type = "Standard_LRS"&lt;br&gt;
     create_option     = "Empty"&lt;br&gt;
     lun               = 0&lt;br&gt;
     disk_size_gb      = "1023"&lt;br&gt;
   }&lt;/p&gt;

&lt;p&gt;storage_data_disk {&lt;br&gt;
     name            = element(azurerm_managed_disk.test.&lt;em&gt;.name, count.index)&lt;br&gt;
     managed_disk_id = element(azurerm_managed_disk.test.&lt;/em&gt;.id, count.index)&lt;br&gt;
     create_option   = "Attach"&lt;br&gt;
     lun             = 1&lt;br&gt;
     disk_size_gb    = element(azurerm_managed_disk.test.*.disk_size_gb, count.index)&lt;br&gt;
   }&lt;/p&gt;

&lt;p&gt;os_profile {&lt;br&gt;
     computer_name  = "hostname"&lt;br&gt;
     admin_username = "testadmin"&lt;br&gt;
     admin_password = "Password1234!"&lt;br&gt;
   }&lt;/p&gt;

&lt;p&gt;os_profile_linux_config {&lt;br&gt;
     disable_password_authentication = false&lt;br&gt;
   }&lt;/p&gt;

&lt;p&gt;tags = {&lt;br&gt;
     environment = "staging"&lt;br&gt;
   }&lt;br&gt;
 }`&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BREAKDOWN OF WHAT SPECIFIC AREAS OF THE CODE DOES.&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;1. Specify the Provider&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;terraform {&lt;br&gt;
  required_providers {&lt;br&gt;
    azurerm = {&lt;br&gt;
      source = "hashicorp/azurerm"&lt;br&gt;
      version = "4.27.0"&lt;br&gt;
    }&lt;br&gt;
  }&lt;br&gt;
}&lt;br&gt;
provider "azurerm" {&lt;br&gt;
    features {}&lt;br&gt;
    subscription_id = "5fdd1cff-4911-4d4a-b28a-969756021e0f"&lt;br&gt;
}&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;These lines tell Terraform to use Azure (azurerm) as the cloud provider and connect to your Azure subscription.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Create a Resource Group&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;resource "azurerm_resource_group" "test" {&lt;br&gt;
   name     = "acctestrg"&lt;br&gt;
   location = "West US 2"&lt;br&gt;
 }&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Creates a resource group in Azure named "acctestrg" where all other resources will live.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Create a Virtual Network&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;resource "azurerm_virtual_network" "test" {&lt;br&gt;
   name                = "acctvn"&lt;br&gt;
   address_space       = ["10.0.0.0/16"]&lt;br&gt;
   location            = azurerm_resource_group.test.location&lt;br&gt;
   resource_group_name = azurerm_resource_group.test.name&lt;br&gt;
 }&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Creates a virtual network (VNet) for your infrastructure with an address space of 10.0.0.0/16.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Create a Subnet inside the VNet&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;resource "azurerm_subnet" "test" {&lt;br&gt;
   name                 = "acctsub"&lt;br&gt;
   resource_group_name  = azurerm_resource_group.test.name&lt;br&gt;
   virtual_network_name = azurerm_virtual_network.test.name&lt;br&gt;
   address_prefixes     = ["10.0.2.0/24"]&lt;br&gt;
 }&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Defines a subnet within the virtual network using 10.0.2.0/24.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Create a Public IP Address&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;resource "azurerm_public_ip" "test" {&lt;br&gt;
   name                         = "publicIPForLB"&lt;br&gt;
   location                     = azurerm_resource_group.test.location&lt;br&gt;
   resource_group_name          = azurerm_resource_group.test.name&lt;br&gt;
   allocation_method            = "Static"&lt;br&gt;
 }&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Sets up a static public IP address to be used by a load balancer.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Create a Load Balancer&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;resource "azurerm_lb" "test" {&lt;br&gt;
   name                = "loadBalancer"&lt;br&gt;
   ...&lt;br&gt;
   frontend_ip_configuration {&lt;br&gt;
     name                 = "publicIPAddress"&lt;br&gt;
     public_ip_address_id = azurerm_public_ip.test.id&lt;br&gt;
   }&lt;br&gt;
 }&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Creates an Azure load balancer using the public IP defined earlier.&lt;/strong&gt;&lt;br&gt;
**&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Define a Backend Pool for Load Balancer**&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;resource "azurerm_lb_backend_address_pool" "test" {&lt;br&gt;
   loadbalancer_id     = azurerm_lb.test.id&lt;br&gt;
   name                = "BackEndAddressPool"&lt;br&gt;
 }&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Creates a backend pool for the load balancer to distribute traffic to virtual machines.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8. Create Network Interfaces (NICs)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;resource "azurerm_network_interface" "test" {&lt;br&gt;
   count               = 2&lt;br&gt;
   ...&lt;br&gt;
   ip_configuration {&lt;br&gt;
     subnet_id                     = azurerm_subnet.test.id&lt;br&gt;
     private_ip_address_allocation = "Dynamic"&lt;br&gt;
   }&lt;br&gt;
 }&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Creates 2 network interfaces that will be attached to the virtual machines and connected to the subnet.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;9. Create Managed Disks&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;resource "azurerm_managed_disk" "test" {&lt;br&gt;
   count                = 2&lt;br&gt;
   ...&lt;br&gt;
   create_option        = "Empty"&lt;br&gt;
   disk_size_gb         = "1023"&lt;br&gt;
 }&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Creates 2 managed data disks (empty, 1023 GB each) that will be attached to the virtual machines.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;10. Create Availability Set&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;resource "azurerm_availability_set" "avset" {&lt;br&gt;
   ...&lt;br&gt;
   managed                      = true&lt;br&gt;
 }&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Creates an availability set to improve high availability of virtual machines by spreading them across fault and update domains.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;11. Create Virtual Machines&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;resource "azurerm_virtual_machine" "test" {&lt;br&gt;
   count                 = 2&lt;br&gt;
   ...&lt;br&gt;
   vm_size               = "Standard_DS1_v2"&lt;br&gt;
   storage_image_reference {&lt;br&gt;
     publisher = "Canonical"&lt;br&gt;
     ...&lt;br&gt;
   }&lt;br&gt;
   os_profile {&lt;br&gt;
     computer_name  = "hostname"&lt;br&gt;
     admin_username = "testadmin"&lt;br&gt;
     admin_password = "Password1234!"&lt;br&gt;
   }&lt;br&gt;
   os_profile_linux_config {&lt;br&gt;
     disable_password_authentication = false&lt;br&gt;
   }&lt;br&gt;
   tags = {&lt;br&gt;
     environment = "staging"&lt;br&gt;
   }&lt;br&gt;
 }&lt;/code&gt;&lt;br&gt;
Creates 2 Ubuntu Linux virtual machines:&lt;/p&gt;

&lt;p&gt;Each VM uses a network interface.&lt;/p&gt;

&lt;p&gt;Attaches one new data disk and one previously created disk.&lt;/p&gt;

&lt;p&gt;Uses an Ubuntu image.&lt;/p&gt;

&lt;p&gt;Sets a username and password.&lt;/p&gt;

&lt;p&gt;Adds a tag for the environment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RUNNING COMMANDS CONTINUE..&lt;/strong&gt;&lt;br&gt;
Run &lt;code&gt;terraform init&lt;/code&gt; again because we have paste into the terminal a fresh command codes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkvrs9c5vd9lzybwbl3x4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkvrs9c5vd9lzybwbl3x4.png" alt="Image description" width="800" height="550"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;terraform plan -out main.tfplan&lt;/code&gt;&lt;br&gt;
The command terraform plan -out main.tfplan creates a plan and saves it to a file named &lt;code&gt;main.tfplan&lt;/code&gt; instead of just showing it on screen.&lt;/p&gt;

&lt;p&gt;It can be noted that when the code was run &lt;code&gt;main.tplan&lt;/code&gt; file was added as shown in the picture below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb8tq35nnecl8goj1a01y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb8tq35nnecl8goj1a01y.png" alt="Image description" width="800" height="488"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LOGGING INTO AZURE&lt;/strong&gt;&lt;br&gt;
Run the code &lt;code&gt;az login&lt;/code&gt;. You will then be pompted to selected the appropriate email attached to your account. Select and click on &lt;strong&gt;Continue&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F02nndoaocenebq4k672d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F02nndoaocenebq4k672d.png" alt="Image description" width="800" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You then be asked to select the active subscription if you have more than one. Input the appropriate number and press the Enter key.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbeeko7v7cq5x260efi9a.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbeeko7v7cq5x260efi9a.jpg" alt="Image description" width="800" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Run the &lt;strong&gt;&lt;code&gt;terraform apply&lt;/code&gt;&lt;/strong&gt; code&lt;br&gt;
&lt;code&gt;terraform apply&lt;/code&gt; actually &lt;strong&gt;executes the changes&lt;/strong&gt; described in your Terraform plan, &lt;strong&gt;creating&lt;/strong&gt;, &lt;strong&gt;updating&lt;/strong&gt;, or &lt;strong&gt;deleting resources in your infrastructure&lt;/strong&gt;. When prompted to enter a value, type yes and press the &lt;strong&gt;Enter key&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;terraform apply&lt;/code&gt; actually &lt;strong&gt;executes the changes&lt;/strong&gt; described in your Terraform plan, creating, updating, or deleting resources in your infrastructure.&lt;/p&gt;

&lt;p&gt;Navigate to Azure and appreciate the resources created automatically without clickings&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnqwu7egz0kt8v5ytutzl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnqwu7egz0kt8v5ytutzl.png" alt="Image description" width="800" height="276"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the first &lt;strong&gt;Resource group&lt;/strong&gt; to view its contents&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1isfxbhqaw3vfe5ns4qf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1isfxbhqaw3vfe5ns4qf.png" alt="Image description" width="800" height="330"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the second Resource group to also view its content&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2nnn0r0gvb2cgbojhirw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2nnn0r0gvb2cgbojhirw.png" alt="Image description" width="800" height="305"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Run the &lt;code&gt;**terraform destroy**&lt;/code&gt; command&lt;br&gt;
&lt;code&gt;terraform destroy&lt;/code&gt; deletes all the &lt;strong&gt;infrastructure resources&lt;/strong&gt; that were created by your &lt;strong&gt;Terraform code&lt;/strong&gt;, effectively &lt;strong&gt;tearing down&lt;/strong&gt; your setup.&lt;/p&gt;

&lt;p&gt;Navigate to Azure portal and ensure all the created resources have been deleted. If not manually delete them to avoid incurring charges.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fva7wsce8soaqkf60xjgw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fva7wsce8soaqkf60xjgw.png" alt="Image description" width="800" height="310"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TAKEHOME FROM THE PROJECT&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Understanding Terraform&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Terraform is an Infrastructure as Code (IaC) tool developed by HashiCorp.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It lets you describe cloud infrastructure in code instead of manually clicking through portals.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can specify resources like:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Resource groups&lt;/li&gt;
&lt;li&gt;Virtual machines&lt;/li&gt;
&lt;li&gt;Databases&lt;/li&gt;
&lt;li&gt;Storage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Terraform uses code to log into cloud providers (like Azure) and build exactly what you describe.&lt;/p&gt;

&lt;p&gt;Analogy: Like a recipe for cloud infrastructure – you write instructions, and Terraform cooks it for you.&lt;/p&gt;

&lt;p&gt;Core Terraform Commands&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setting Up Terraform on Windows&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Method A: Manual Installation&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Download Terraform from the &lt;strong&gt;official site&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Choose the correct version (amd64 for modern 64-bit systems).&lt;/li&gt;
&lt;li&gt;Extract the downloaded ZIP folder.&lt;/li&gt;
&lt;li&gt;Copy the path of the Terraform executable.&lt;/li&gt;
&lt;li&gt;Add the path to your Windows Environment Variables under the System Path.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Method B: Using Chocolatey&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open PowerShell as Administrator.&lt;/li&gt;
&lt;li&gt;Ensure Chocolatey is installed.&lt;/li&gt;
&lt;li&gt;Run choco install terraform.&lt;/li&gt;
&lt;li&gt;Confirm installation by running terraform --version.&lt;/li&gt;
&lt;li&gt;Preparing GitHub for Terraform Projects&lt;/li&gt;
&lt;li&gt;Create a GitHub account if you don’t have one.&lt;/li&gt;
&lt;li&gt;Create a new repository (e.g., Repo1).&lt;/li&gt;
&lt;li&gt;Enable README creation in the new repo.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Copy the &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;HTTP URL for cloning (easiest method for VS Code).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cloning GitHub Repository in VS Code&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Install Terraform extension in VS Code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Open Source Control → Clone Repository → Paste URL or select GitHub repo.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create/select a folder for the project.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Confirm cloning and open the repo in VS Code.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Creating the &lt;code&gt;main.tf&lt;/code&gt; File&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;main.tf is the primary configuration file where resources are declared.&lt;/li&gt;
&lt;li&gt;It acts like the instruction sheet for Terraform.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Connecting Terraform to Azure&lt;/strong&gt;&lt;br&gt;
Providers are plugins that allow Terraform to communicate with external systems (like Azure).&lt;/p&gt;

&lt;p&gt;Visit Terraform Registry and select Azure Provider.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Copy and paste provider block into main.tf.&lt;/li&gt;
&lt;li&gt;Modify the config to include:&lt;/li&gt;
&lt;li&gt;features {} block&lt;/li&gt;
&lt;li&gt;Your Azure subscription_id (inside quotes)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Running Terraform Commands in VS Code&lt;/strong&gt;&lt;br&gt;
Open a new terminal in VS Code.&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;terraform init&lt;/code&gt; to initialize and lock dependencies.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;.terraform.lock.hcl&lt;/code&gt; file is generated after &lt;code&gt;init&lt;/code&gt; for dependency consistency.&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>azure</category>
      <category>githubactions</category>
      <category>infrastructureascode</category>
    </item>
    <item>
      <title>Building an Azure Web App.</title>
      <dc:creator>Bala Audu Musa</dc:creator>
      <pubDate>Fri, 04 Apr 2025 07:54:19 +0000</pubDate>
      <link>https://dev.to/bala_audu_musa/building-an-azure-web-app-25og</link>
      <guid>https://dev.to/bala_audu_musa/building-an-azure-web-app-25og</guid>
      <description>&lt;p&gt;&lt;strong&gt;Objective:&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Our objective this time as a DevOps Engineer is to build a web application following a cloud-first approach and hosting the application on Azure App Service.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Our tasks:&lt;/strong&gt;&lt;br&gt;
i. Pushing the application code to GitHub using Git Bash&lt;br&gt;
ii. Deploying the application to Azure App Service using Azure CLI&lt;/p&gt;

&lt;p&gt;For better understanding of what are getting ourselves into, let us understand some key GitHub terminologies;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fork:&lt;/strong&gt; To create a copy of the original repository.&lt;br&gt;
&lt;strong&gt;Clone:&lt;/strong&gt; To download a copy of the forked repository to your machine.&lt;br&gt;
&lt;strong&gt;Branch:&lt;/strong&gt; To create a new branch to work on your changes.&lt;br&gt;
&lt;strong&gt;Commit: **To save your changes to the repository.&lt;br&gt;
**Push: **To upload your changes to your remote repository.&lt;br&gt;
**Pull Request:&lt;/strong&gt; To submit your changes for review.&lt;br&gt;
&lt;strong&gt;Repository:&lt;/strong&gt; A repository (or repo) in GitHub is a storage location where your project files, including code, documentation, and other resources, are kept. It tracks changes to these files over time, allowing collaboration, version control, and backup of your work.&lt;/p&gt;

&lt;p&gt;NOW LET'S GET STARTED.&lt;/p&gt;

&lt;p&gt;a) Create a new repository in Github. Give the repository a name. In this case &lt;strong&gt;Ittisalat App.&lt;/strong&gt; Give it a description. Determine who can commit to the repository. In this case left it in the default &lt;strong&gt;Public&lt;/strong&gt;. Tick the box of Add a README. README File usually contains an introduction to the project, instructions, or documentation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F41kgh43nfiuiwx8ul7m3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F41kgh43nfiuiwx8ul7m3.png" alt="Image description" width="800" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;b) Select from the drop-down options of Add .gitignore. This basically choose which files not to track from a list of templates. In this case I had none. Hence, I selected &lt;strong&gt;.gitignore template: None&lt;/strong&gt;. Same for &lt;strong&gt;Choose a license **. A license tells others what they can and can't do with your code. Then click on **Create repository.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkiy4jizaj10qlnswwtgz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkiy4jizaj10qlnswwtgz.png" alt="Image description" width="800" height="342"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We are now going to create an index file in Git Bash and Push to GitHub. &lt;/p&gt;

&lt;p&gt;c) Open Git Bash and click on &lt;strong&gt;Run as administrator&lt;/strong&gt;. It will prompt you if you want this app to make changes to your device. Click on yes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv4y5vq6y8ssj02udmtyh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv4y5vq6y8ssj02udmtyh.png" alt="Image description" width="800" height="414"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;d)  Configure the Git Bash environment by typing the following commands into the terminal.&lt;br&gt;
 To Configure username as in Git Hub:&lt;br&gt;
&lt;strong&gt;git config --global user.name Bamboo-cod&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To configure useremail address:&lt;br&gt;
&lt;strong&gt;git config --global user.email &lt;a href="mailto:freshabdullaah@mail.com"&gt;freshabdullaah@mail.com&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Create a directory:&lt;br&gt;
Type &lt;strong&gt;mkdir IttisalatApp&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Enter into the just created directory by typing the command;&lt;br&gt;
&lt;strong&gt;cd IttisalatApp&lt;/strong&gt;. We can now see that we are now inside the directory depicted by the forward slash "/" before our directory name. Shown in the yellow box.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8wa64d0jktsef9d8d7lk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8wa64d0jktsef9d8d7lk.png" alt="Image description" width="800" height="225"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Initialize the created directory on the local host&lt;br&gt;
&lt;strong&gt;git init&lt;/strong&gt; + ENTER Button&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkcedk1p3j7tvj4yqpfm5.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkcedk1p3j7tvj4yqpfm5.PNG" alt="Image description" width="527" height="44"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Link git terminal to github.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create an &lt;strong&gt;index.html&lt;/strong&gt; file on git using this command:&lt;br&gt;
&lt;strong&gt;touch index.html&lt;/strong&gt; + Enter button&lt;/p&gt;

&lt;p&gt;In order to input the index.html code open up an editor in the git terminal using the following command:&lt;br&gt;
&lt;strong&gt;vi index.html&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flwcgsu1bwqjtoeb1f155.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flwcgsu1bwqjtoeb1f155.PNG" alt="Image description" width="579" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Use any of the artificial intelligence application like **Chatgpt, Perplexity or Deepseek **to generate an html code for the particular app you want to create. For example I typed in the following prompt into Deepseek ai: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fthxzaekq955ejucxo0rw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fthxzaekq955ejucxo0rw.png" alt="Image description" width="800" height="164"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The following result was generated (cut):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvmw08stbezh5igbolnq3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvmw08stbezh5igbolnq3.png" alt="Image description" width="752" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Copy and paste the html code into the text editor. Inorder to paste type the "i" button. Right click and then paste. Ensure the code is well aligned.&lt;/p&gt;

&lt;p&gt;Snapshot of the code in git; &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2sj87fxra9o4b2sqh6by.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2sj87fxra9o4b2sqh6by.png" alt="Image description" width="580" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Save and exit editor by pressing the ESC button and colon (:)wq + Enter button.&lt;/p&gt;

&lt;p&gt;Go to your Github account click on the green Code button and copy https code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa9ljoheayieor0nepoh6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa9ljoheayieor0nepoh6.png" alt="Image description" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg16cemwgud89dufd6xdu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg16cemwgud89dufd6xdu.png" alt="Image description" width="800" height="294"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go back to the terminal and type in the following command:&lt;br&gt;
*&lt;em&gt;**git remote add origin&lt;/em&gt;&lt;em&gt;leave a space &lt;a href="https://github.com/bamboo-cod/IttisalatApp.git" rel="noopener noreferrer"&gt;https://github.com/bamboo-cod/IttisalatApp.git&lt;/a&gt;&lt;/em&gt;*&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjn6s49ck96xvzsj3p7y5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjn6s49ck96xvzsj3p7y5.png" alt="Image description" width="593" height="67"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The command **git remote add origin &lt;a href="https://github.com/bamboo-cod/IttisalatApp.git" rel="noopener noreferrer"&gt;https://github.com/bamboo-cod/IttisalatApp.git&lt;/a&gt; **links your local Git repository to a remote repository on GitHub.&lt;/p&gt;

&lt;p&gt;Then type the command &lt;strong&gt;git add index.html&lt;/strong&gt; The command &lt;strong&gt;git add index.html&lt;/strong&gt; &lt;strong&gt;stages&lt;/strong&gt; the index.html file in Git, preparing it to be included in your next &lt;strong&gt;commit&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj7lgwnayiql4bzxkp2ai.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj7lgwnayiql4bzxkp2ai.png" alt="Image description" width="800" height="516"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Type the following code&lt;br&gt;
&lt;strong&gt;git commit -m "My first social App"&lt;/strong&gt; and enter.&lt;/p&gt;

&lt;p&gt;Inorder to move the master branch, type the following command&lt;br&gt;
&lt;strong&gt;git push origin master&lt;/strong&gt; and enter&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjfq1w7vtbe333fmp5y5q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjfq1w7vtbe333fmp5y5q.png" alt="Image description" width="584" height="371"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go back to Github and check your code. You might be asked to verify and authenticate. Tick on compare and pull request.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmqhh6xykcovsr5s4ivv4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmqhh6xykcovsr5s4ivv4.png" alt="Image description" width="800" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Type in az login into the GitBass terminal&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzkali89w1sb3p2kczuam.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzkali89w1sb3p2kczuam.png" alt="Image description" width="606" height="230"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It will then prompt you to sign in. Select the appropriate email linked to your azure account and click on continue.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi13b4mhve3gwt38ymmzg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi13b4mhve3gwt38ymmzg.png" alt="Image description" width="361" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The terminal could not recognize my subscription. So i had to type the following prompt: *&lt;em&gt;az login --tenant 42cbee7b-bcaa-4a28-9f5f-1cf6f023a10d&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
output: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv981gn1zoywjwtz91oof.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv981gn1zoywjwtz91oof.png" alt="Image description" width="512" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create a Resource Group if you dont have one. Input the following command:&lt;strong&gt;az group create --name IttisalatApp(i.e: name of your resource group in azure) -location uksouth&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foklrmqbsltrk83jzgfor.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foklrmqbsltrk83jzgfor.png" alt="Image description" width="438" height="403"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create an &lt;strong&gt;App Servicer Plan&lt;/strong&gt;. An App Service Plan in Azure is a foundational component that defines the compute resources and configuration for hosting web applications, APIs, mobile backends, and other services within Azure App Service. &lt;/p&gt;

&lt;p&gt;Type into the terminal the following command: &lt;br&gt;
&lt;strong&gt;az appservice plan create --name IttisalatAppServ --resource-group IttisalatApp&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I got an error:- &lt;strong&gt;MissingSubscriptionRegistration&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Meaning:&lt;/strong&gt; My Azure subscription lacks the necessary registration for the Microsoft.Web resource provider, which is required for Azure App Service (and related resources like App Service Plans).&lt;/p&gt;

&lt;p&gt;I had to rectify this problem by doing the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Register the &lt;strong&gt;Microsoft.Web&lt;/strong&gt; provider using the Azure CLI:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;az provider register --namespace Microsoft.Web&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Verifying the registration status by typing into the terminal the following command:
&lt;strong&gt;az provider show --namespace Microsoft.Web --query "registrationState"&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Create the Web App using the following command: &lt;strong&gt;az webapp create --name IttisalatWebApp --resource-group IttisalatApp --plan IttisalatAppServ&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A quick run on History shows the commands so far:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj6xss999l2b04j445jmm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj6xss999l2b04j445jmm.png" alt="Image description" width="631" height="199"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deployment of the Web App&lt;br&gt;
**&lt;br&gt;
**az webapp deployment source config --name IttisalatApp --resource-group IttisalatApp --repo-url &lt;a href="https://github.com/bamboo-cod/IttisalatApp.git" rel="noopener noreferrer"&gt;https://github.com/bamboo-cod/IttisalatApp.git&lt;/a&gt; --branch master --manual-integration&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This command does &lt;strong&gt;one simple thing&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Connects your Azure Web App (named "IttisalatApp") to a GitHub repository&lt;/strong&gt; so that you can deploy code manually from the &lt;code&gt;master&lt;/code&gt; branch of that repo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Breakdown:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;az webapp deployment source config&lt;/code&gt;&lt;/strong&gt;:
&lt;em&gt;"Set up where the app's code comes from."&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;--name IttisalatApp&lt;/code&gt;&lt;/strong&gt;:
&lt;em&gt;"The name of your Azure Web App."&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;--resource-group IttisalatApp&lt;/code&gt;&lt;/strong&gt;:
&lt;em&gt;"The resource group where your app lives in Azure."&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;--repo-url https://github.com/...&lt;/code&gt;&lt;/strong&gt;:
&lt;em&gt;"Link to your GitHub code repository."&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;--branch master&lt;/code&gt;&lt;/strong&gt;:
&lt;em&gt;"Use code from the &lt;code&gt;master&lt;/code&gt; branch of the repo."&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;--manual-integration&lt;/code&gt;&lt;/strong&gt;:
&lt;em&gt;"Azure won’t auto-deploy when you push code to GitHub. You’ll have to trigger deployments manually."&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What happens next?
&lt;/h3&gt;

&lt;p&gt;After running this command:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Azure knows where your code is stored (GitHub).
&lt;/li&gt;
&lt;li&gt;When you’re ready to deploy, you’ll need to manually &lt;strong&gt;sync&lt;/strong&gt; or &lt;strong&gt;trigger a deployment&lt;/strong&gt; (e.g., via the Azure Portal or CLI).
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdu15kge5rshz1t9ln808.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdu15kge5rshz1t9ln808.png" alt="Image description" width="625" height="363"&gt;&lt;/a&gt;&lt;br&gt;
This shows we have successfully deploy our web app.&lt;/p&gt;

&lt;p&gt;To verify log into the azure account.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqjbgeu8vdk1uxs1xsn3z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqjbgeu8vdk1uxs1xsn3z.png" alt="Image description" width="800" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clicking on the Default domain url: &lt;strong&gt;ittisalatwebapp.azurewebsites.net&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F278vrkw72e9qlefx1l5p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F278vrkw72e9qlefx1l5p.png" alt="Image description" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Creating a deployment slot&lt;/strong&gt;&lt;br&gt;
A deployment slot in Azure is like a separate, isolated instance of your web app that allows you to test changes in a staging environment before swapping it with production. Think of it as a "copy" of your live app where you can safely deploy and validate updates without affecting real users.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxrttgjuv9dbfhyo09lsd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxrttgjuv9dbfhyo09lsd.png" alt="Image description" width="547" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on Upgrade&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faxu4fo5vig89liys1gmx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faxu4fo5vig89liys1gmx.png" alt="Image description" width="625" height="156"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select the first premium service&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbhjnx3knk97vi5th9u3c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbhjnx3knk97vi5th9u3c.png" alt="Image description" width="800" height="336"&gt;&lt;/a&gt;&lt;br&gt;
Click on select and Upgrade&lt;/p&gt;

&lt;p&gt;Click on Add Slot&lt;br&gt;
Give the slot a name and click on add&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpccrcigv1cqxd94ud14q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpccrcigv1cqxd94ud14q.png" alt="Image description" width="453" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fughzvcnw4nhfx4hr0xhy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fughzvcnw4nhfx4hr0xhy.png" alt="Image description" width="430" height="430"&gt;&lt;/a&gt;&lt;br&gt;
After working on the readjustment of the webapp in the background, click on swap to grant full traffic to users.&lt;/p&gt;

</description>
      <category>webapp</category>
      <category>azure</category>
      <category>gitbash</category>
    </item>
  </channel>
</rss>
