Variables & Data Types and Basic Math Operations

What is a Variable?

Think of a variable like a box with a label on it.

You put something inside the box, and you use the label to find it later.

name = "Gagan"

Here:

  • name is the label (variable name)
  • "Gagan" is the value stored inside it
  • = means "store this value in this variable"

Now whenever you use name in your code, Python knows it means "Gagan".


Your First Variable Program


    name = "Gagan"
    age = 22
    print(name)
    print(age)

Output:

Gagan
22

Simple! You stored two values and printed them.


Variable Naming Rules

Not everything is allowed as a variable name. Here are the rules:

Allowed:

my_name = "Gagan"       # underscore is allowed
age2 = 25               # numbers allowed (not at start)
firstName = "Gagan"     # camelCase is allowed

NOT Allowed:

2age = 25          # cannot start with a number
my-name = "Gagan"  # hyphen not allowed
my name = "Gagan"  # spaces not allowed

Best Practice: Use lowercase with underscores for variable names. This is called snake_case and it's the Python standard:


    first_name = "Gagan"
    phone_number = 9876543210
    is_student = True


Data Types

Every value in Python has a type. Python has several built-in data types. As a beginner, these 4 are the most important:


1. String (str) — Text

Any text inside quotes is a string:


    name = "Gagan"
    city = "Delhi"
    message = "I love Python"

    print(type(name))   # <class 'str'>

type() tells you what type a variable is. Very useful for debugging.


2. Integer (int) — Whole Numbers

Numbers without decimal points:


    age = 22
    year = 2025
    students = 100

    print(type(age))   # <class 'int'>


3. Float (float) — Decimal Numbers

Numbers with decimal points:


    price = 99.99
    height = 5.11
    temperature = 36.6

    print(type(price))   # <class 'float'>


4. Boolean (bool) — True or False

Only two possible values — True or False:


    is_student = True
    has_job = False
    is_raining = True

    print(type(is_student))   # <class 'bool'>

Important: True and False must start with capital letters. true or false will give an error.


Using Variables with print()

You can combine variables and text in print using f-strings (the modern way):


    name = "Gagan"
    age = 22
    city = "Delhi"

    print(f"My name is {name}")
    print(f"I am {age} years old")
    print(f"I live in {city}")
    print(f"My name is {name} and I am {age} years old")

Output:

My name is Gagan
I am 22 years old
I live in Delhi
My name is Gagan and I am 22 years old

The f before the quote makes it an f-string. Inside {} curly brackets you write your variable name and Python automatically puts its value there.

This is the most used and cleanest way to print variables in modern Python.


Updating Variables

You can change the value of a variable anytime:


    score = 0
    print(f"Score: {score}")

    score = 10
    print(f"Score: {score}")

    score = 50
    print(f"Score: {score}")

Output:

Score: 0
Score: 10
Score: 50

The variable just gets updated with the new value.


Multiple Variables in One Line

Python allows this shortcut:


    x, y, z = 10, 20, 30
    print(x)   # 10
    print(y)   # 20
    print(z)   # 30

Or assign the same value to multiple variables:


    a = b = c = 0
    print(a, b, c)   # 0 0 0


A Complete Example

Let's put it all together:


    # Personal Information
    name = "Gagan"
    age = 22
    city = "Delhi"
    height = 5.11
    is_student = True

    print(f"Name: {name}")
    print(f"Age: {age}")
    print(f"City: {city}")
    print(f"Height: {height}")
    print(f"Student: {is_student}")
    print(f"Data type of name: {type(name)}")
    print(f"Data type of age: {type(age)}")

Output:

Name: Gagan
Age: 22
City: Delhi
Height: 5.11
Student: True
Data type of name: <class 'str'>
Data type of age: <class 'int'>

Exercise 🏋️

Create a program that stores this information in variables and prints it using f-strings:

  • Your name
  • Your age
  • Your favorite subject
  • Your city
  • Whether you are a student (True/False)

Expected output format:

Hello! My name is [name]
I am [age] years old
My favorite subject is [subject]
I live in [city]
Am I a student? [True/False]

Try it yourself!


Basic Math Operations

Python as a Calculator

Python can do all kinds of math. Think of it as a very powerful calculator.

Let's start simple:


    print(2 + 3)    # 5
    print(10 - 4)   # 6
    print(3 * 4)    # 12
    print(10 / 2)   # 5.0


All Math Operators in Python

Operator

Name

Example

Result

+

Addition

5 + 3

8

-

Subtraction

5 - 3

2

*

Multiplication

5 * 3

15

/

Division

10 / 3

3.333...

//

Floor Division

10 // 3

3

%

Modulus

10 % 3

1

**

Power / Exponent

2 ** 3

8

Let's understand each one properly.


Addition, Subtraction, Multiplication — Simple


    a = 10
    b = 3

    print(a + b)   # 13
    print(a - b)   # 7
    print(a * b)   # 30

Nothing surprising here. Works exactly like normal math.


Division / — Always Returns Float


    print(10 / 2)   # 5.0   (not 5, notice the .0)
    print(7 / 2)    # 3.5
    print(10 / 3)   # 3.3333333333333335

Regular division always returns a float even if the answer is a whole number. That's why 10 / 2 gives 5.0 not 5.


Floor Division // — Removes the Decimal


    print(10 // 3)   # 3   (3.33... becomes 3, decimal removed)
    print(7 // 2)    # 3   (3.5 becomes 3)
    print(15 // 4)   # 3   (3.75 becomes 3)

Floor division divides and then rounds down to the nearest whole number. Decimal part is just thrown away.


Modulus % — Gives the Remainder

This one confuses beginners at first but it's very useful:


    print(10 % 3)   # 1   (10 divided by 3 = 3, remainder is 1)
    print(15 % 4)   # 3   (15 divided by 4 = 3, remainder is 3)
    print(10 % 2)   # 0   (10 divided by 2 = 5, remainder is 0)

Think of it like this — when you divide 10 by 3:

  • 3 goes into 10 exactly 3 times (that's 9)
  • What's left over is 1
  • So 10 % 3 = 1

Most common use case: Checking if a number is even or odd:


    number = 7
    print(number % 2)   # 1 — odd (remainder is 1)

    number = 8
    print(number % 2)   # 0 — even (remainder is 0)

If number % 2 is 0 → even. If it's 1 → odd. You'll use this a LOT in future.


Power ** — Exponents


    print(2 ** 3)    # 8    (2 * 2 * 2)
    print(5 ** 2)    # 25   (5 * 5)
    print(3 ** 4)    # 81   (3 * 3 * 3 * 3)
    print(9 ** 0.5)  # 3.0  (square root of 9)


Math with Variables

You'll almost never do math with raw numbers. You'll use variables:


    price = 500
    quantity = 3
    discount = 50

    total = price * quantity
    final_price = total - discount

    print(f"Price per item: {price}")
    print(f"Quantity: {quantity}")
    print(f"Total before discount: {total}")
    print(f"Discount: {discount}")
    print(f"Final price: {final_price}")

Output:

Price per item: 500
Quantity: 3
Total before discount: 1500
Discount: 50
Final price: 1450

Shorthand Operators

These are shortcuts to update a variable's value:


    score = 10

    score = score + 5   # normal way
    score += 5          # shorthand — same thing

    score = score - 3
    score -= 3          # shorthand

    score = score * 2
    score *= 2          # shorthand

    score = score / 2
    score /= 2          # shorthand

Full example:


    score = 0
    print(f"Start: {score}")

    score += 10
    print(f"After +10: {score}")

    score += 5
    print(f"After +5: {score}")

    score -= 3
    print(f"After -3: {score}")

    score *= 2
    print(f"After *2: {score}")

Output:

Start: 0
After +10: 10
After +5: 15
After -3: 12
After *2: 24

Order of Operations (BODMAS)

Python follows the same math rules you learned in school — BODMAS/PEMDAS:

  1. Brackets ()
  2. Exponents **
  3. Multiplication *, Division /, Floor Division //, Modulus %
  4. Addition +, Subtraction -

    print(2 + 3 * 4)      # 14  (multiplication first, then addition)
    print((2 + 3) * 4)    # 20  (brackets first)
    print(10 - 2 + 3)     # 11  (left to right)
    print(2 ** 3 + 1)     # 9   (exponent first, then addition)

When in doubt — use brackets to make your intention clear:

result = (price * quantity) - discount   # clear and readable

Type Conversion in Math

Sometimes you'll have a number stored as a string and need to do math with it. Direct math won't work:


    a = "10"   # this is a string, not a number
    b = 5

    print(a + b)   # ERROR! can't add string and number

You need to convert it first:


    a = "10"
    b = 5

    a = int(a)     # convert string to integer
    print(a + b)   # 15 — works now!

Conversion functions:

  • int() — converts to integer
  • float() — converts to float
  • str() — converts to string

    print(int("25"))       # 25
    print(float("3.14"))   # 3.14
    print(str(100))        # "100"
    print(int(9.99))       # 9  (decimal part is cut off, not rounded)


Real World Example — Simple Bill Calculator


    item1 = 150
    item2 = 250
    item3 = 100

    subtotal = item1 + item2 + item3
    tax = subtotal * 0.18        # 18% GST
    total = subtotal + tax

    print(f"Item 1: Rs.{item1}")
    print(f"Item 2: Rs.{item2}")
    print(f"Item 3: Rs.{item3}")
    print(f"Subtotal: Rs.{subtotal}")
    print(f"GST (18%): Rs.{tax}")
    print(f"Total Bill: Rs.{total}")

Output:

Item 1: Rs.150
Item 2: Rs.250
Item 3: Rs.100
Subtotal: Rs.500
GST (18%): Rs.90.0
Total Bill: Rs.590.0

Exercise 🏋️

Write a program that:

  1. Stores two numbers in variables a = 17 and b = 5
  2. Prints the result of all 7 operations on them (addition, subtraction, multiplication, division, floor division, modulus, power)
  3. Also prints whether a is even or odd using modulus operator

Expected output format:

a = 17, b = 5
Addition: 22
Subtraction: 12
Multiplication: 85
Division: 3.4
Floor Division: 3
Modulus (Remainder): 2
Power: 1419857
Is a even? False  (hint: use a % 2 == 0)

Don't worry about the last line for now — we'll properly learn == in the next step. Just try your best!


Installing Python and Your First Python Program

Step 1: Installing Python

Let's start from the very beginning — getting Python on your computer.


How to Download & Install Python

Step 1: Go to the official website — python.org

Step 2: Click on the Downloads button. It will automatically detect your operating system (Windows/Mac/Linux) and suggest the latest version.

Step 3: Download Python 3.13.x (whatever the latest 3.13 version is shown)

Step 4: Run the installer


IMPORTANT — Windows Users (Read This Carefully)

When the installer opens, you will see a checkbox at the bottom that says:

☐ Add Python to PATH

CHECK THIS BOX BEFORE CLICKING INSTALL.

This is the most common beginner mistake. If you skip this, Python won't work from your terminal/command prompt.

After checking that box, click "Install Now" and wait for it to finish.


Verify Installation

After installing, let's confirm Python is working correctly.

On Windows:

  • Press Windows + R, type cmd, press Enter
  • A black window (Command Prompt) will open
  • Type this and press Enter:
python --version

On Mac/Linux:

  • Open Terminal
  • Type:
python3 --version

You should see something like:

Python 3.13.1

If you see this — Python is successfully installed! 🎉

If you see an error like "python is not recognized" — it means you forgot to check the PATH checkbox. In that case, uninstall Python and install again, this time checking that box.


Installing VS Code (Code Editor)

Python is installed. Now you need a place to write your code. We'll use VS Code — it's free and the most popular editor.

Step 1: Go to code.visualstudio.com

Step 2: Download for your OS and install it (simple next-next-finish installation)

Step 3: Open VS Code

Step 4: On the left side, click the Extensions icon (looks like 4 squares)

Step 5: Search for "Python" — install the one made by Microsoft (it has millions of downloads)

This extension helps VS Code understand Python code — gives you suggestions, highlights errors, etc.


Setting Up Your First Project Folder

Good habit from day one — keep your code organized.

Step 1: Create a folder on your Desktop or anywhere you like. Name it something like python-learning

Step 2: Open VS Code → File → Open Folder → select your python-learning folder

Step 3: Inside VS Code, create a new file → name it hello.py

The .py extension tells your computer "this is a Python file"


Step 2: Your First Python Program

The Tradition — "Hello, World!"

In programming, when you learn any new language, the very first program everyone writes is called "Hello, World!". It's a tradition since the 1970s. So let's follow it!


Writing Your First Program

Open the hello.py file you created in VS Code and type this:


    print("Hello, World!")

That's it. This is a complete, valid Python program.


Running Your Program

Method 1 — Using VS Code Terminal:

In VS Code, go to Terminal → New Terminal (or press Ctrl + backtick)

A terminal will open at the bottom of VS Code. Type:

python hello.py

On Mac/Linux:

python3 hello.py

Press Enter. You will see:

Hello, World!

Method 2 — Using the Play Button:

In VS Code, you'll see a ▶ Play button on the top right corner. Just click it and it runs your file directly.


What is print()?

print() is a function that displays text on the screen.

Whatever you write inside the brackets () with quotes, it will show on screen.

Let's try a few more examples. Update your file:


    print("Hello, World!")
    print("My name is Gagan")
    print("I am learning Python")
    print("This is my first program!")

Run it. Output:

Hello, World!
My name is Gagan
I am learning Python
This is my first program!

Each print() starts on a new line automatically.


Quotes — Single or Double?

Both work in Python. These two lines do the exact same thing:


    print("Hello, World!")
    print('Hello, World!')

You can use single quotes ' ' or double quotes " " — your choice. Just be consistent. Most people use double quotes.


What Happens If You Make a Mistake?

Let's intentionally break the code so you understand errors:


    print("Hello, World!"

Run this. You'll see:

SyntaxError: '(' was never closed

This is called a Syntax Error — it means your code has a typo or something is missing. Here the closing bracket ) is missing.

Fix it back:


    print("Hello, World!")

Important mindset: Errors are normal. Every programmer gets errors daily. Don't panic when you see one — just read it carefully and it usually tells you what went wrong.


Comments — Notes in Your Code

Sometimes you want to write notes in your code that Python should ignore. These are called comments.

Use the # symbol:


    # This is my first Python program
    print("Hello, World!")  # This prints a message

    # Python will ignore everything after the # symbol
    # print("This line will NOT run")
    print("But this line will run")

Output:

Hello, World!
But this line will run

Comments are very useful for:

  • Explaining what your code does
  • Temporarily disabling a line without deleting it
  • Leaving notes for yourself or others

Your First Exercise 🏋️

Write a program that prints the following output exactly:

Welcome to Python!
My name is [your name]
I am a beginner
Let's learn together!

Use 4 separate print() statements. Try it yourself first, then move to the next step.

Python Learning Roadmap for Beginners

Welcome! Python is one of the best first programming languages. It's simple, readable, and used everywhere — web development, data science, AI, automation, and more.


What You Need to Know Before Starting

Nothing! Seriously. Python is beginner-friendly. You just need:

  • A computer (Windows, Mac, or Linux — all work)
  • Basic computer skills (how to open files, use a browser)
  • Curiosity and patience

That's it. No prior coding experience needed.


Current Python Version

Always use Python 3.13 (latest stable as of 2025). Never use Python 2 — it's dead.


Your Complete Python Learning Roadmap

Stage 1 — Setup & Basics (Week 1-2)

This is where we start. You'll learn:

  • How to install Python
  • How to write your first program
  • Variables and data types (numbers, text, etc.)
  • Taking input from user
  • Basic math operations
  • Comments in code

Stage 2 — Control Flow (Week 2-3)

  • If / else conditions
  • Loops — for loop, while loop
  • Break and continue

Stage 3 — Functions (Week 3-4)

  • What is a function and why we need it
  • Creating and calling functions
  • Parameters and return values
  • Scope (local vs global variables)

Stage 4 — Data Structures (Week 4-5)

  • Lists
  • Tuples
  • Dictionaries
  • Sets
  • When to use which one

Stage 5 — String Handling (Week 5)

  • String methods
  • String formatting (f-strings)
  • Slicing strings

Stage 6 — File Handling (Week 6)

  • Reading files
  • Writing files
  • Working with paths

Stage 7 — Error Handling (Week 6)

  • Try / except
  • Common errors and how to fix them

Stage 8 — Modules & Libraries (Week 7)

  • What is a module
  • Importing built-in modules
  • Installing external libraries with pip
  • Important built-in modules: os, math, random, datetime

Stage 9 — Object Oriented Programming / OOP (Week 8-9)

  • Classes and Objects
  • Constructor (init)
  • Methods
  • Inheritance
  • Encapsulation

Stage 10 — Pythonic Code & Best Practices (Week 9-10)

  • List comprehensions
  • Lambda functions
  • Map, filter
  • Writing clean code

Complete Beginner Guide: Node.js + Express API with Docker, Docker Hub, AWS EC2 & CI/CD

WHAT WE ARE BUILDING

A simple Node.js Express REST API with 2 endpoints. One GET endpoint that returns a welcome message. One POST endpoint that receives a JSON payload and sends back a response with the received data. We will containerize it with Docker, push to Docker Hub, host on AWS EC2, and set up CI/CD with GitHub Actions so every code push auto-deploys.


TOOLS NEEDED (Same as before, skip if already installed)

To verify Node.js installed, open VS Code terminal and type:

node --version
npm --version

Both should show version numbers.


ACCOUNTS NEEDED


PART 1 — CREATE THE PROJECT

Step 1: Create Project Folder

Open File Explorer → go to C:\Users\YourName\ → create a new folder named node-api

Step 2: Open in VS Code

Right-click the node-api folder → "Open with Code"

Step 3: Create the Folder Structure

In VS Code Explorer panel, create this structure:

node-api/
├── src/
│   └── index.js
├── .github/
│   └── workflows/
│       └── cicd.yml
├── Dockerfile
├── .dockerignore
└── package.json

How to create:

  • Click New Folder icon → type "src" → Enter
  • Click New Folder icon → type ".github" → Enter
  • Click on .github → New Folder → type "workflows" → Enter
  • Click on src → New File → type "index.js" → Enter
  • Click on workflows → New File → type "cicd.yml" → Enter
  • Click on root node-api → New File → type "Dockerfile" → Enter
  • New File → type ".dockerignore" → Enter

We will create package.json using a command, not manually.


PART 2 — INITIALIZE NODE PROJECT

Step 4: Open Terminal in VS Code

Press Ctrl + ` to open the terminal at the bottom.

Step 5: Initialize the Project

npm init -y

This creates a package.json file automatically with default values. The -y means yes to all questions. You will see the file appear in your Explorer panel.

Step 6: Install Express

npm install express

This installs Express and creates a node_modules folder and package-lock.json file. Express is the framework we use to create API endpoints easily.

After this your folder looks like:

node-api/
├── node_modules/        ← auto created, do not touch
├── src/
│   └── index.js
├── .github/
│   └── workflows/
│       └── cicd.yml
├── Dockerfile
├── .dockerignore
├── package.json         ← auto created by npm init
└── package-lock.json    ← auto created by npm install

PART 3 — WRITE THE CODE

Step 7: Write index.js (The Main API File)

Click on src/index.js in VS Code and paste this:


    const express = require('express');

    const app = express();
    const PORT = process.env.PORT || 3000;

    // This middleware allows Express to read JSON from request body
    app.use(express.json());

    // ─────────────────────────────────────────
    // GET /
    // Simple welcome endpoint
    // ─────────────────────────────────────────
    app.get('/', (req, res) => {
        res.json({
            success: true,
            message: 'Welcome to my Node.js Express API!',
            version: '1.0.0',
            endpoints: {
                GET: 'GET /api/greet?name=YourName',
                POST: 'POST /api/message  →  body: { "name": "...", "text": "..." }'
            }
        });
    });

    // ─────────────────────────────────────────
    // GET /api/greet
    // Returns a greeting message
    // Optional query param: ?name=YourName
    // Example: GET /api/greet?name=Rahul
    // ─────────────────────────────────────────
    app.get('/api/greet', (req, res) => {
        const name = req.query.name || 'Guest';

        res.json({
            success: true,
            message: `Hello, ${name}! Welcome to the API.`,
            timestamp: new Date().toISOString()
        });
    });

    // ─────────────────────────────────────────
    // POST /api/message
    // Receives a JSON payload and sends it back
    // Expected body: { "name": "...", "text": "..." }
    // Example: POST /api/message
    //   body: { "name": "Rahul", "text": "Hello from client" }
    // ─────────────────────────────────────────
    app.post('/api/message', (req, res) => {
        const { name, text } = req.body;

        // Validate that required fields are present
        if (!name || !text) {
            return res.status(400).json({
                success: false,
                message: 'Both name and text fields are required in the request body.',
                example: {
                    name: 'Rahul',
                    text: 'Hello from client'
                }
            });
        }

        res.status(201).json({
            success: true,
            message: 'Payload received successfully!',
            received: {
                name: name,
                text: text
            },
            response: `Hi ${name}! We got your message: "${text}"`,
            timestamp: new Date().toISOString()
        });
    });

    // ─────────────────────────────────────────
    // Handle unknown routes
    // ─────────────────────────────────────────
    app.use((req, res) => {
        res.status(404).json({
            success: false,
            message: `Route ${req.method} ${req.url} not found.`
        });
    });

    // ─────────────────────────────────────────
    // Start the server
    // ─────────────────────────────────────────
    app.listen(PORT, () => {
        console.log(`Server is running on port ${PORT}`);
        console.log(`Local URL: http://localhost:${PORT}`);
    });

Step 8: Update package.json

Open package.json. It was auto-created by npm init. Replace the entire content with this:

{
  "name": "node-api",
  "version": "1.0.0",
  "description": "Simple Node.js Express REST API",
  "main": "src/index.js",
  "scripts": {
    "start": "node src/index.js",
    "dev": "node src/index.js"
  },
  "dependencies": {
    "express": "^4.18.2"
  }
}

The start script is important because Docker will use npm start to run the app.

Step 9: Write Dockerfile

Click on Dockerfile and paste this:

# Use official Node.js LTS image based on Alpine (small and fast)
FROM node:20-alpine

# Set working directory inside the container
WORKDIR /app

# Copy package.json and package-lock.json first
# We copy these separately so Docker can cache the npm install layer
# This means if only your code changes, npm install won't run again
COPY package*.json ./

# Install dependencies
RUN npm install --production

# Copy the rest of your application code
COPY src/ ./src/

# Tell Docker this app uses port 3000
EXPOSE 3000

# Command to start the app
CMD ["npm", "start"]

Step 10: Write .dockerignore

Click on .dockerignore and paste this:

node_modules
npm-debug.log
.git
.github
*.md
.env

We ignore node_modules because Docker will install them fresh inside the container using npm install. No need to copy them from your machine.


PART 4 — TEST LOCALLY WITHOUT DOCKER FIRST

Step 11: Run the API on Your Machine

In VS Code terminal:

npm start

You will see:

Server is running on port 3000
Local URL: http://localhost:3000

Step 12: Test the API Endpoints

Open your browser and go to http://localhost:3000. You will see the welcome JSON response.

Now test the GET endpoint. Open browser and go to:

http://localhost:3000/api/greet?name=Rahul

You will see:

{
  "success": true,
  "message": "Hello, Rahul! Welcome to the API.",
  "timestamp": "2026-01-01T10:00:00.000Z"
}

To test the POST endpoint you need a tool because browsers cannot send POST requests directly. Use one of these options:

Option A: Use Thunder Client in VS Code (GUI, Recommended for beginners)

In VS Code, click the Extensions icon (left sidebar, looks like 4 squares). Search "Thunder Client". Install it. Then click the Thunder Client icon in the left sidebar. Click "New Request". Set method to POST. URL: http://localhost:3000/api/message. Click "Body" tab → select "JSON". Paste this in the body:

{
  "name": "Rahul",
  "text": "Hello from Thunder Client"
}

Click Send. You will see the response on the right side.

Option B: Use curl in terminal (CLI)

Open a new terminal (click the + icon in terminal panel) while the server is still running in the first terminal. Run:

curl -X POST http://localhost:3000/api/message -H "Content-Type: application/json" -d "{\"name\": \"Rahul\", \"text\": \"Hello from curl\"}"

You will see:

{
  "success": true,
  "message": "Payload received successfully!",
  "received": {
    "name": "Rahul",
    "text": "Hello from curl"
  },
  "response": "Hi Rahul! We got your message: \"Hello from curl\"",
  "timestamp": "2026-01-01T10:00:00.000Z"
}

Stop the server: press Ctrl+C in the terminal where npm start is running.


PART 5 — TEST WITH DOCKER LOCALLY

Step 13: Build Docker Image

Make sure Docker Desktop is running (whale icon in taskbar). In VS Code terminal:

docker build -t node-api:latest .

You will see Docker going through each step in the Dockerfile. Wait for "Successfully built" message.

GUI verification: Open Docker Desktop → click "Images" → you will see "node-api" listed.

Step 14: Run the Container

docker run -d -p 3000:3000 --name node-api-test node-api:latest

Step 15: Test the Containerized API

Open browser → http://localhost:3000. Same response as before but now running inside Docker.

Test GET: http://localhost:3000/api/greet?name=Docker

Test POST using Thunder Client or curl same as Step 12 but now it is hitting the container.

Step 16: Stop and Remove Test Container

CLI Way:

docker stop node-api-test
docker rm node-api-test

GUI Way: Docker Desktop → Containers → click Stop → click Delete on node-api-test.


PART 6 — DOCKER HUB SETUP

Step 17: Create Docker Hub Repository

  1. Go to https://hub.docker.com and log in
  2. Click "Create Repository"
  3. Name: node-api
  4. Visibility: Public (important — keeps it simple, no login needed to pull)
  5. Click Create

Step 18: Create Docker Hub Access Token

  1. Docker Hub → click your profile photo → Account Settings
  2. Click Security in left menu
  3. Click "New Access Token"
  4. Name: github-actions-token
  5. Permissions: Read, Write, Delete
  6. Click Generate
  7. COPY THE TOKEN and save in Notepad. You will not see it again.

Step 19: Push Image to Docker Hub

In VS Code terminal:

docker login

Enter your Docker Hub username and password.

docker tag node-api:latest yourusername/node-api:latest
docker push yourusername/node-api:latest

Go to https://hub.docker.com/r/yourusername/node-api and verify the image is there with "latest" tag.


PART 7 — PUSH TO GITHUB

Step 20: Create GitHub Repository

GUI Way using GitHub Desktop:

  1. Open GitHub Desktop
  2. Click "Add an Existing Repository from your Hard Drive"
  3. Browse to your node-api folder → Select Folder
  4. It will say "not a git repository" → click "create a repository" link
  5. Name: node-api
  6. Click "Create Repository"
  7. Click "Publish repository" at the top
  8. Uncheck "Keep this code private" if you want public
  9. Click "Publish Repository"

CLI Way:

git init
git add .
git commit -m "Initial commit: Node.js Express API"

Go to https://github.com → click + → New repository → name it "node-api" → Create repository. Then copy the commands GitHub shows you and run them. They look like:

git remote add origin https://github.com/yourusername/node-api.git
git branch -M main
git push -u origin main

PART 8 — AWS EC2 SETUP

If you already have an EC2 instance from the previous project with Docker installed, you can reuse it. Just make sure port 3000 is open in the security group. Skip to Step 22 if reusing.

Step 21: Create New EC2 Instance (Skip if reusing old one)

  1. Go to https://console.aws.amazon.com

  2. Search "EC2" in top search bar → click EC2

  3. Click orange "Launch Instance" button

  4. Fill in settings:

    Name: node-api-server

    AMI: Amazon Linux 2023 (Free tier eligible)

    Instance type: t2.micro (Free tier eligible)

    Key pair: Click "Create new key pair"

    • Name: node-api-key
    • Type: RSA
    • Format: .pem
    • Click Create key pair
    • Save the downloaded .pem file to C:\Users\YourName.ssh\

    Network settings → click Edit:

    • Rule 1: SSH, port 22, Source: My IP
    • Rule 2: HTTP, port 80, Source: Anywhere 0.0.0.0/0
    • Click "Add security group rule":
    • Rule 3: Custom TCP, port 3000, Source: Anywhere 0.0.0.0/0 (this is for our Node API)
  5. Click "Launch Instance"

  6. Click "View all instances"

  7. Wait for status to show "Running" with green dot

  8. Note the Public IPv4 address (example: 13.235.xxx.xxx)

Step 22: Install Docker on EC2

GUI Way: In AWS Console → EC2 → Instances → select your instance → click "Connect" → "EC2 Instance Connect" tab → click "Connect". Browser terminal opens.

CLI Way: Open VS Code terminal and run:

ssh -i C:\Users\YourName\.ssh\node-api-key.pem ec2-user@YOUR_EC2_PUBLIC_IP

Now run these commands in the EC2 terminal:

sudo yum update -y
sudo yum install docker -y
sudo systemctl start docker
sudo systemctl enable docker
sudo usermod -aG docker ec2-user

Close the terminal and reconnect. Then verify:

docker --version

PART 9 — ADD GITHUB SECRETS

Step 23: Add Secrets to GitHub Repository

Go to https://github.com/yourusername/node-api → Settings tab → Secrets and variables → Actions → New repository secret.

Add these 5 secrets:

Secret 1:

  • Name: DOCKERHUB_USERNAME
  • Value: your Docker Hub username

Secret 2:

  • Name: DOCKERHUB_TOKEN
  • Value: the token you saved in Notepad from Step 18

Secret 3:

  • Name: EC2_HOST
  • Value: your EC2 public IP address (example: 13.235.243.85)

Secret 4:

  • Name: EC2_USERNAME
  • Value: ec2-user

Secret 5:

  • Name: EC2_SSH_KEY
  • Value: open your .pem file in VS Code, select all (Ctrl+A), copy, paste here. Make sure the entire content is there including the first line "-----BEGIN RSA PRIVATE KEY-----" and last line "-----END RSA PRIVATE KEY-----"

PART 10 — CREATE CI/CD PIPELINE

Step 24: Write cicd.yml

Click on .github/workflows/cicd.yml in VS Code and paste this complete final file:

name: CI/CD Pipeline - Node API

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

jobs:

  # ================================
  # JOB 1: Build and Push to Docker Hub
  # ================================
  build-and-push:
    name: Build and Push Docker Image
    runs-on: ubuntu-latest

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

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

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

      - name: Build and Push image to Docker Hub
        uses: docker/build-push-action@v5
        with:
          context: .
          push: ${{ github.event_name != 'pull_request' }}
          tags: |
            ${{ secrets.DOCKERHUB_USERNAME }}/node-api:latest
            ${{ secrets.DOCKERHUB_USERNAME }}/node-api:${{ github.sha }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

  # ================================
  # JOB 2: Deploy to AWS EC2
  # ================================
  deploy:
    name: Deploy to AWS EC2
    runs-on: ubuntu-latest
    needs: build-and-push
    if: github.ref == 'refs/heads/main' && github.event_name == 'push'

    steps:
      - name: SSH into EC2 and Deploy
        uses: appleboy/ssh-action@v1.0.3
        with:
          host: ${{ secrets.EC2_HOST }}
          username: ${{ secrets.EC2_USERNAME }}
          key: ${{ secrets.EC2_SSH_KEY }}
          script: |
            # Login to Docker Hub (handles private repos too)
            echo "${{ secrets.DOCKERHUB_TOKEN }}" | docker login -u "${{ secrets.DOCKERHUB_USERNAME }}" --password-stdin

            # Pull the latest image
            docker pull ${{ secrets.DOCKERHUB_USERNAME }}/node-api:latest

            # Stop and remove old container if it exists
            docker stop node-api || true
            docker rm node-api || true

            # Run new container
            docker run -d \
              --name node-api \
              --restart unless-stopped \
              -p 3000:3000 \
              ${{ secrets.DOCKERHUB_USERNAME }}/node-api:latest

            # Clean up old unused images to save disk space
            docker image prune -f

            echo "Deployment successful! API is live."

PART 11 — DEPLOY

Step 25: Push Everything to GitHub

GUI Way using GitHub Desktop:

  1. Open GitHub Desktop
  2. You will see all your files listed on the left as changes
  3. In the Summary field at bottom left type: Add Node.js Express API with Docker and CI/CD
  4. Click "Commit to main"
  5. Click "Push origin" at the top

CLI Way:

git add .
git commit -m "Add Node.js Express API with Docker and CI/CD"
git push origin main

Step 26: Watch the Pipeline Run

  1. Go to https://github.com/yourusername/node-api
  2. Click the "Actions" tab
  3. You will see a workflow running with a yellow spinner
  4. Click on it to open
  5. Watch Job 1 "Build and Push Docker Image" run — takes about 2-3 minutes
  6. Watch Job 2 "Deploy to AWS EC2" run — takes about 1 minute
  7. Both should show green checkmarks when done

If any job fails, click on it to see the error log and share a screenshot.

Step 27: Test Your Live API on AWS

Open your browser and go to:

http://YOUR_EC2_PUBLIC_IP:3000

You will see the welcome JSON. Now test the GET endpoint:

http://YOUR_EC2_PUBLIC_IP:3000/api/greet?name=Rahul

To test the POST endpoint, use Thunder Client in VS Code. Create a new POST request. URL: http://YOUR_EC2_PUBLIC_IP:3000/api/message. Body JSON:

{
  "name": "Rahul",
  "text": "Hello from my deployed API!"
}

Send. You will get:

{
  "success": true,
  "message": "Payload received successfully!",
  "received": {
    "name": "Rahul",
    "text": "Hello from my deployed API!"
  },
  "response": "Hi Rahul! We got your message: \"Hello from my deployed API!\"",
  "timestamp": "2026-01-01T10:00:00.000Z"
}

COMPLETE FOLDER STRUCTURE (Final)

node-api/
├── .github/
│   └── workflows/
│       └── cicd.yml          ← GitHub Actions pipeline
├── src/
│   └── index.js              ← Express API with GET and POST endpoints
├── node_modules/             ← Auto created by npm install, do not touch
├── .dockerignore             ← Files to ignore when building Docker image
├── Dockerfile                ← Instructions to build Docker image
├── package.json              ← Project info and dependencies
└── package-lock.json         ← Auto created by npm install

API ENDPOINTS SUMMARY

GET  /                        → Welcome message and list of endpoints
GET  /api/greet               → Returns greeting (optional ?name=YourName)
POST /api/message             → Receives JSON payload, returns it back

COMPLETE FLOW

You write code in VS Code
         ↓
Push to GitHub via GitHub Desktop or git push
         ↓
GitHub Actions triggers automatically
         ↓
Job 1: Builds Docker image → Pushes to Docker Hub
         ↓
Job 2: SSH into EC2 → docker login → docker pull → docker run
         ↓
API is live at http://YOUR_EC2_IP:3000

HOW TO UPDATE THE API EVERY TIME

Make any change in src/index.js. For example add a new endpoint or change a message. Then:

GitHub Desktop: write commit message → Commit to main → Push origin.

CLI: git add . → git commit -m "your message" → git push origin main.

GitHub Actions runs automatically. In 3-4 minutes your changes are live on AWS without touching the server manually.

Complete Beginner Guide: Deploy HTML/CSS/JS Website with Docker, Docker Hub, AWS & CI/CD

WHAT WE ARE BUILDING

You will write a simple website (HTML + CSS + JS), put it inside Docker, upload it to Docker Hub, host it on AWS, and set up automatic deployment so every time you change your code and push to GitHub, your website updates itself on AWS automatically.


TOOLS WE NEED

Before starting anything, install these tools on your Windows 11 machine.

1. VS Code (Code Editor) Go to https://code.visualstudio.com → Download for Windows → Install it. This is where you write your code.

2. Git Go to https://git-scm.com/download/win → Download → Install with all default options. This is needed even if you use GitHub Desktop.

3. GitHub Desktop (GUI Option) Go to https://desktop.github.com → Download → Install → Sign in with your GitHub account. This lets you push code without using any commands.

4. Docker Desktop Go to https://www.docker.com/products/docker-desktop → Download for Windows → Install. During installation make sure "Use WSL 2 instead of Hyper-V" is checked. After install, restart your PC. Open Docker Desktop and sign in with your Docker Hub account (create one at https://hub.docker.com if you don't have one).

5. Accounts You Need


PART 1 — CREATE YOUR PROJECT

Step 1: Create the Project Folder

Open File Explorer on your Windows 11. Go to C drive, then your Users folder, then your username folder. Create a new folder and name it "my-website". The full path will be something like C:\Users\YourName\my-website.

Step 2: Open the Folder in VS Code

Two ways to do this:

GUI Way: Right-click on the my-website folder → you will see "Open with Code" in the menu → click it.

CLI Way: Open the folder in File Explorer, then click on the address bar at the top, type "cmd" and press Enter. A black command prompt window opens. Then type:

code .

This opens VS Code in that folder.

Step 3: Create the Folder Structure

In VS Code, on the left side you see the Explorer panel. You will create folders and files there.

To create a folder: Click the "New Folder" icon (it looks like a folder with a plus sign) in the Explorer panel. To create a file: Click the "New File" icon (it looks like a paper with a plus sign).

Create this exact structure:

my-website/
├── src/
│   ├── index.html
│   ├── css/
│   │   └── style.css
│   └── js/
│       └── main.js
├── .github/
│   └── workflows/
│       └── cicd.yml
├── Dockerfile
├── nginx.conf
└── .dockerignore

How to create it step by step:

  • Click New Folder icon → type "src" → press Enter
  • Click on the src folder to select it → click New Folder icon → type "css" → press Enter
  • Click on the src folder again → click New Folder icon → type "js" → press Enter
  • Click New Folder icon at root level → type ".github" → press Enter
  • Click on .github folder → click New Folder icon → type "workflows" → press Enter
  • Now create files: click on src folder → New File → "index.html"
  • Click on css folder → New File → "style.css"
  • Click on js folder → New File → "main.js"
  • Click on workflows folder → New File → "cicd.yml"
  • Click on root (my-website) level → New File → "Dockerfile" (no extension, exactly this)
  • New File → "nginx.conf"
  • New File → ".dockerignore"

PART 2 — WRITE THE CODE

Step 4: Write index.html

Click on index.html in VS Code and paste this:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
  <title>My Website</title>
  <link rel="stylesheet" href="css/style.css" />
</head>
<body>
  <div class="container">
    <h1>Hello World!</h1>
    <p id="message">My website is live on AWS with Docker and CI/CD!</p>
    <button id="btn">Click Me</button>
  </div>
  <script src="js/main.js"></script>
</body>
</html>

Notice that the CSS file is linked using href="css/style.css" and the JS file is linked at the bottom using src="js/main.js". This is how separate files connect to HTML.

Step 5: Write style.css

Click on style.css and paste this:

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  font-family: Arial, sans-serif;
  background: linear-gradient(135deg, #1a1a2e, #16213e);
  color: white;
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
}

.container {
  text-align: center;
  padding: 40px;
  background: rgba(255, 255, 255, 0.05);
  border-radius: 16px;
  border: 1px solid rgba(255, 255, 255, 0.1);
}

h1 {
  font-size: 2.5rem;
  margin-bottom: 16px;
  color: #e94560;
}

p {
  font-size: 1.1rem;
  margin-bottom: 24px;
  color: #a8b2d8;
}

button {
  padding: 12px 32px;
  background: #e94560;
  color: white;
  border: none;
  border-radius: 8px;
  font-size: 1rem;
  cursor: pointer;
}

button:hover {
  background: #c73652;
}

Step 6: Write main.js

Click on main.js and paste this:

document.getElementById('btn').addEventListener('click', function() {
  document.getElementById('message').textContent = 'JavaScript is working! CI/CD pipeline deployed this.';
  document.getElementById('btn').textContent = 'Clicked!';
  document.getElementById('btn').style.background = '#2ecc71';
});

Step 7: Write nginx.conf

Nginx is a web server that will serve your HTML files inside Docker. Click on nginx.conf and paste this:

server {
    listen 80;
    server_name localhost;
    root /usr/share/nginx/html;
    index index.html;

    location / {
        try_files $uri $uri/ /index.html;
    }
}

Step 8: Write Dockerfile

The Dockerfile tells Docker how to package your website. Click on Dockerfile and paste this:

# Use official nginx image based on Alpine Linux (small and fast)
FROM nginx:alpine

# Remove the default nginx config file
RUN rm /etc/nginx/conf.d/default.conf

# Copy our custom nginx config
COPY nginx.conf /etc/nginx/conf.d/default.conf

# Copy our website files into the nginx web root folder
COPY src/ /usr/share/nginx/html/

# Tell Docker this container uses port 80
EXPOSE 80

# Start nginx when container runs
CMD ["nginx", "-g", "daemon off;"]

Step 9: Write .dockerignore

This tells Docker to ignore certain files when building. Click on .dockerignore and paste this:

.git
.github
*.md

PART 3 — TEST LOCALLY WITH DOCKER

Step 10: Open Terminal in VS Code

In VS Code, press Ctrl + ` (backtick key, below Escape key). This opens a terminal at the bottom.

Make sure Docker Desktop is running (you should see the Docker whale icon in your taskbar).

Step 11: Build the Docker Image

In the terminal, type this command and press Enter:

docker build -t my-website:latest .

What this means: "docker build" means build an image, "-t my-website:latest" means name it "my-website" with tag "latest", and the dot "." means use the current folder.

You will see Docker downloading things and running steps. Wait for it to finish. You will see "Successfully built" at the end.

GUI Way to verify: Open Docker Desktop → click "Images" on the left sidebar → you will see "my-website" listed there.

Step 12: Run the Container Locally

docker run -d -p 8080:80 --name my-website-test my-website:latest

What this means: "-d" means run in background, "-p 8080:80" means map your computer's port 8080 to the container's port 80, "--name my-website-test" gives the container a name.

Now open your browser and go to: http://localhost:8080

You should see your website! If it works, your Docker setup is correct.

To stop the container:

CLI Way:

docker stop my-website-test
docker rm my-website-test

GUI Way: Open Docker Desktop → click "Containers" on the left → you will see "my-website-test" → click the Stop button (square icon) → then click the Delete button (trash icon).


PART 4 — PUSH TO GITHUB

Step 13: Initialize Git and Push to GitHub

GUI Way using GitHub Desktop:

  1. Open GitHub Desktop
  2. Click "Add an Existing Repository from your Hard Drive"
  3. Click "Choose" and browse to your my-website folder → click "Select Folder"
  4. It will say "This directory does not appear to be a Git repository" → click "create a repository" link
  5. Name: my-website
  6. Local path: already set to your folder
  7. Click "Create Repository"
  8. Now click "Publish repository" button at the top
  9. Uncheck "Keep this code private" if you want it public (you can keep private too)
  10. Click "Publish Repository"
  11. Your code is now on GitHub. You can verify by going to https://github.com/yourusername/my-website

CLI Way:

Open terminal in VS Code and run these commands one by one:

git init
git add .
git commit -m "Initial commit: add website and Docker files"

Now go to https://github.com, log in, click the "+" button at top right, click "New repository", name it "my-website", leave other settings default, click "Create repository".

GitHub will show you commands. Copy and run them. They look like this:

git remote add origin https://github.com/yourusername/my-website.git
git branch -M main
git push -u origin main

Replace "yourusername" with your actual GitHub username.


PART 5 — DOCKER HUB SETUP

Step 14: Create a Docker Hub Repository

  1. Go to https://hub.docker.com and log in
  2. Click the "Create Repository" button (blue button)
  3. Repository name: my-website
  4. Visibility: Private
  5. Click "Create"

Your Docker Hub repo address will be: hub.docker.com/r/yourusername/my-website

Step 15: Create a Docker Hub Access Token

This token is like a password that GitHub Actions will use to push images to Docker Hub. You never share your actual password with GitHub.

  1. On Docker Hub, click your profile photo (top right) → "Account Settings"
  2. Click "Security" in the left menu
  3. Click "New Access Token"
  4. Name it: github-actions
  5. Access permissions: Read, Write, Delete
  6. Click "Generate"
  7. A token will appear on screen — COPY IT NOW and save it in Notepad. You will never see this again after closing the window.

Step 16: Push Your Image to Docker Hub (Test)

In VS Code terminal:

docker tag my-website:latest yourusername/my-website:latest
docker push yourusername/my-website:latest

Before pushing, you may need to login in the terminal:

docker login

Enter your Docker Hub username and password.

GUI Way to push: Actually for pushing from your local machine, the terminal commands above are the simplest. Docker Desktop does not have a direct "push" button, so just use the 2 commands above.

After pushing, go to https://hub.docker.com/r/yourusername/my-website and you should see your image listed there with the "latest" tag.


PART 6 — AWS SETUP

Step 17: Create AWS Account

Go to https://aws.amazon.com and click "Create an AWS Account". Fill in your email, password, and account name. You will need a credit or debit card but will not be charged as long as you use free tier resources. Complete phone verification and sign in to the AWS Console at https://console.aws.amazon.com.

Step 18: Create an EC2 Instance (Your Server on AWS)

EC2 is basically a computer that runs 24/7 in the cloud. This is where your website will live.

GUI Way (AWS Console):

  1. In the AWS Console, look at the top search bar. Type "EC2" and click on EC2 from the results.

  2. You will see the EC2 Dashboard. Click the orange "Launch Instance" button.

  3. On the "Launch an instance" page, fill in these settings:

    Under "Name and tags":

    • Name: my-website-server

    Under "Application and OS Images":

    • Click on "Amazon Linux" (it should already be selected)
    • Make sure "Amazon Linux 2023 AMI" is selected
    • You should see "Free tier eligible" next to it

    Under "Instance type":

    • Select "t2.micro"
    • You should see "Free tier eligible" next to it

    Under "Key pair (login)":

    • Click "Create new key pair"
    • Key pair name: my-website-key
    • Key pair type: RSA
    • Private key file format: .pem
    • Click "Create key pair"
    • A file called "my-website-key.pem" will automatically download to your Downloads folder
    • MOVE THIS FILE to C:\Users\YourName.ssh\ folder. Create the .ssh folder if it doesn't exist. This file is very important — it's how you access your server. Do not lose it.

    Under "Network settings":

    • Click the "Edit" button on the right side
    • You will see one rule for SSH (port 22). In the "Source type" dropdown for this rule, select "My IP". This means only your computer can SSH into the server.
    • Click "Add security group rule" to add a second rule:
      • Type: HTTP
      • Protocol: TCP
      • Port range: 80
      • Source type: Anywhere (0.0.0.0/0)
      • This allows everyone to access your website on port 80
    • Click "Add security group rule" again for a third rule:
      • Type: HTTPS
      • Protocol: TCP
      • Port range: 443
      • Source type: Anywhere (0.0.0.0/0)

    Under "Configure storage":

    • Keep default 8 GB
  4. Click the orange "Launch instance" button on the right side summary panel.

  5. Click "View all instances".

  6. You will see your instance. Wait about 1-2 minutes until the "Instance state" column shows "Running" with a green dot. Refresh the page if needed.

  7. Click on your instance name to open its details. Look for "Public IPv4 address" on the right side. Write down this IP address. It looks something like 13.233.45.67. This is your server's address.

Step 19: Connect to Your EC2 Server and Install Docker

You need to go inside your server and install Docker on it.

GUI Way (using EC2 Instance Connect in browser):

  1. In AWS Console, go to EC2 → Instances → click on your instance
  2. Click the "Connect" button at the top
  3. Click on the "EC2 Instance Connect" tab
  4. Username should say "ec2-user" — leave it as is
  5. Click the orange "Connect" button
  6. A browser terminal window opens. You are now inside your server!

CLI Way (using terminal on Windows):

Open VS Code terminal and run:

ssh -i C:\Users\YourName\.ssh\my-website-key.pem ec2-user@YOUR_EC2_PUBLIC_IP

Replace YOUR_EC2_PUBLIC_IP with the IP you noted in step 18.

If you get a permission error on Windows, you need to fix the .pem file permissions. Right-click the .pem file → Properties → Security → Advanced → Disable inheritance → Remove all inherited permissions → Add → Select a principal → type your Windows username → Full control → OK.

Now whether you used GUI or CLI, you are in the server terminal. Run these commands:

sudo yum update -y

Wait for it to finish. This updates the server's software.

sudo yum install docker -y

This installs Docker on the server.

sudo systemctl start docker

This starts Docker.

sudo systemctl enable docker

This makes Docker start automatically if the server restarts.

sudo usermod -aG docker ec2-user

This allows ec2-user to run Docker commands without typing "sudo" each time.

docker --version

This confirms Docker is installed. You should see a version number.

You can close this terminal window. The server is ready.


PART 7 — ADD SECRETS TO GITHUB

Step 20: Add Repository Secrets

GitHub Actions (your CI/CD pipeline) needs some private information like your Docker Hub token and AWS server details. You store these as "secrets" in GitHub so they are not visible in your code.

  1. Go to https://github.com/yourusername/my-website
  2. Click the "Settings" tab (it's in the top navigation of your repo, not your account settings)
  3. In the left sidebar, scroll down and click "Secrets and variables"
  4. Click "Actions" under it
  5. You will see a "Repository secrets" section
  6. Click the "New repository secret" button

Add these 5 secrets one by one:

Secret 1:

  • Name: DOCKERHUB_USERNAME
  • Secret: your Docker Hub username (just the username, nothing else)
  • Click "Add secret"

Secret 2:

  • Name: DOCKERHUB_TOKEN
  • Secret: paste the token you copied and saved in Notepad from Step 15
  • Click "Add secret"

Secret 3:

  • Name: EC2_HOST
  • Secret: your EC2 public IP address (e.g., 13.233.45.67)
  • Click "Add secret"

Secret 4:

  • Name: EC2_USERNAME
  • Secret: ec2-user
  • Click "Add secret"

Secret 5:

  • Name: EC2_SSH_KEY
  • Secret: you need to paste the entire content of your .pem file here
  • To get the content: go to VS Code → File → Open File → browse to C:\Users\YourName.ssh\my-website-key.pem → open it → press Ctrl+A to select all → Ctrl+C to copy
  • Paste it as the secret value
  • Click "Add secret"

You should now see 5 secrets listed. These are encrypted and nobody can see them except GitHub Actions when it runs.


PART 8 — CREATE THE CI/CD PIPELINE

Step 21: Write the GitHub Actions Workflow

Click on cicd.yml in VS Code (it's in .github/workflows/ folder) and paste this:

name: CI/CD Pipeline

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

jobs:

  # ================================
  # JOB 1: Build and Push to Docker Hub
  # ================================
  build-and-push:
    name: Build and Push Docker Image
    runs-on: ubuntu-latest

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

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

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

      - name: Build and Push image to Docker Hub
        uses: docker/build-push-action@v5
        with:
          context: .
          push: ${{ github.event_name != 'pull_request' }}
          tags: |
            ${{ secrets.DOCKERHUB_USERNAME }}/my-website:latest
            ${{ secrets.DOCKERHUB_USERNAME }}/my-website:${{ github.sha }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

  # ================================
  # JOB 2: Deploy to AWS EC2
  # ================================
  deploy:
    name: Deploy to AWS EC2
    runs-on: ubuntu-latest
    needs: build-and-push
    if: github.ref == 'refs/heads/main' && github.event_name == 'push'

    steps:
      - name: SSH into EC2 and Deploy
        uses: appleboy/ssh-action@v1.0.3
        with:
          host: ${{ secrets.EC2_HOST }}
          username: ${{ secrets.EC2_USERNAME }}
          key: ${{ secrets.EC2_SSH_KEY }}
          script: |
            # Step 1: Login to Docker Hub (fixes private repo issue)
            echo "${{ secrets.DOCKERHUB_TOKEN }}" | docker login -u "${{ secrets.DOCKERHUB_USERNAME }}" --password-stdin

            # Step 2: Pull the latest image
            docker pull ${{ secrets.DOCKERHUB_USERNAME }}/my-website:latest

            # Step 3: Stop and remove old container if running
            docker stop my-website || true
            docker rm my-website || true

            # Step 4: Run new container
            docker run -d \
              --name my-website \
              --restart unless-stopped \
              -p 80:80 \
              ${{ secrets.DOCKERHUB_USERNAME }}/my-website:latest

            # Step 5: Clean up old unused images
            docker image prune -f

            echo "Deployment successful! Website is live."

Save the file with Ctrl+S.

Let me explain what this pipeline does in simple words. When you push code to the main branch on GitHub, GitHub Actions automatically starts two jobs. The first job called "build-and-push" picks up your code, builds a Docker image from it, and pushes that image to Docker Hub. The second job called "deploy" only runs after the first job succeeds. It connects to your AWS EC2 server via SSH, pulls the new Docker image from Docker Hub, stops the old container that was running, and starts a new container with the new image. Your website is then updated.


PART 9 — PUSH EVERYTHING AND GO LIVE

Step 22: Push All Files to GitHub

You now have all your files ready. Push everything to GitHub.

GUI Way using GitHub Desktop:

  1. Open GitHub Desktop
  2. On the left side you will see all your changed files listed
  3. At the bottom left, in the "Summary" field type: Add all project files with CI/CD pipeline
  4. Click "Commit to main"
  5. Click "Push origin" button at the top

CLI Way:

In VS Code terminal:

git add .
git commit -m "Add all project files with CI/CD pipeline"
git push origin main

Step 23: Watch the Pipeline Run

  1. Go to https://github.com/yourusername/my-website
  2. Click the "Actions" tab in the top navigation
  3. You will see a workflow run starting. It will have a yellow circle which means it is running.
  4. Click on the workflow run to open it
  5. You will see two jobs: "Build and Push Docker Image to Docker Hub" and "Deploy to AWS EC2"
  6. Click on any job to see its real-time logs
  7. The build job takes about 2-3 minutes
  8. The deploy job takes about 1 minute
  9. When both jobs show green checkmarks, your website is deployed

If any job fails, click on it and read the error message. Common issues are wrong secret values or wrong EC2 IP.

Step 24: See Your Live Website

Open your browser and type:

http://YOUR_EC2_PUBLIC_IP

For example: http://13.233.45.67

Your website is now live on the internet, running on AWS!


PART 10 — HOW TO UPDATE YOUR WEBSITE

This is the beauty of CI/CD. Every time you want to update your website, you just change your code and push. Everything else happens automatically.

For example, open src/index.html and change "Hello World!" to "Hello World! Updated!". Save the file.

GUI Way: Open GitHub Desktop → you see the changed file → write a commit message → Commit to main → Push origin.

CLI Way:

git add .
git commit -m "Update heading text"
git push origin main

Then go to GitHub Actions tab and watch the pipeline run. In about 3-4 minutes your change will be live on AWS automatically.


FINAL FOLDER STRUCTURE (What You Should Have)

my-website/
│
├── .github/
│   └── workflows/
│       └── cicd.yml         ← GitHub Actions pipeline
│
├── src/
│   ├── index.html           ← Main HTML file
│   ├── css/
│   │   └── style.css        ← All styling
│   └── js/
│       └── main.js          ← All JavaScript
│
├── Dockerfile               ← Instructions to build Docker image
├── nginx.conf               ← Nginx web server config
└── .dockerignore            ← Files to ignore when building Docker image

COMPLETE FLOW IN SIMPLE WORDS

You write code in VS Code on your Windows 11 laptop. You push the code to GitHub using GitHub Desktop (clicking) or git push (typing). GitHub sees new code on the main branch and automatically starts the CI/CD pipeline. The pipeline builds a Docker image of your website and uploads it to Docker Hub. Then the pipeline connects to your AWS server and tells it to download the new image and restart the website container. Your website is updated on the internet without you doing anything manually on the server.


TROUBLESHOOTING COMMON ISSUES

Docker Desktop not starting: Make sure virtualization is enabled in your BIOS. On Windows 11 it should be on by default. Also make sure WSL 2 is installed. Open PowerShell as Administrator and run: wsl --install

Permission denied when pushing to Docker Hub: Make sure you are logged in. Run "docker login" in terminal and enter your credentials.

GitHub Actions failing at deploy step: Double-check your EC2_SSH_KEY secret. Open your .pem file in VS Code, make sure you copied the ENTIRE content including the first line "-----BEGIN RSA PRIVATE KEY-----" and the last line "-----END RSA PRIVATE KEY-----".

Website not opening on EC2 IP: Check that port 80 is open in your EC2 security group. Go to AWS Console → EC2 → Security Groups → find your security group → check Inbound rules → HTTP port 80 should be there with source 0.0.0.0/0.

SSH connection refused when using CLI: Make sure your EC2 instance is in Running state. Also make sure the Security Group has port 22 open for your IP. Your IP might have changed if you are on a home network — go to Security Group rules and update the SSH source to "Anywhere" temporarily for testing, then change back to your IP.

Phase 3 — Components Deep Dive

Chapter 1 — What We Are Going to Learn and Why In Phase 2 you learned what a component is and how to create one. You know that a component h...