This guide will walk you through hosting your site using a secure, high-performance architecture. Here, we’ll use cloudfront default url to access the website but you can use a domain name via Route 53 if handy.

  • Goal: Host a static personal portfolio, but with a focus on security, performance, and cost.
  • Business Problem: Creating a professional online presence that is fast, secure, and cheap to maintain.
  • What you’ll learn: Securely storing files, global content delivery, hosting website and basic web security.

Build Portfolio Website Using AWS Services

Services Used :

  • S3 (for hosting)
  • CloudFront (CDN)
  • AWS WAF (Web Application Firewall)

Step 1: Create a Private S3 Bucket

This bucket will store your website files (index.html, etc.).

  1. Navigate to S3: In the AWS Console, go to the S3 service.
  2. Create Bucket: Click “Create bucket”.
    • Bucket name: Give it a unique name (e.g., yourname-portfolio-source-files).
    • AWS Region: Choose a region close to you (e.g., us-east-1).
  3. Block Public Access: This is the most critical security step. Ensure “Block all public access” is checked. We will grant access only to our CDN later.
  4. Create: Click “Create bucket”.
  5. Upload Files: Go into your new bucket and click “Upload”. Add the index.html file and any other assets you have. Refer to below sample code.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>My Cloud Portfolio</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700&display=swap" rel="stylesheet">
    <style>
        body {
            font-family: 'Inter', sans-serif;
        }
        .gradient-text {
            background: linear-gradient(to right, #3b82f6, #8b5cf6);
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
        }
    </style>
</head>
<body class="bg-gray-900 text-gray-200">

    <div class="container mx-auto max-w-4xl px-4 py-8 md:py-16">

        <!-- Header Section -->
        <header class="flex flex-col md:flex-row items-center justify-between mb-12">
            <div class="flex items-center mb-6 md:mb-0">
                <img src="https://placehold.co/80x80/1f2937/a5b4fc?text=ME" alt="Your Name" class="w-20 h-20 rounded-full mr-4 border-2 border-blue-400">
                <div>
                    <h1 class="text-3xl font-bold text-white">Your Name</h1>
                    <p class="text-lg text-blue-300">Aspiring Cloud & DevOps Engineer</p>
                </div>
            </div>
            <nav class="flex space-x-6">
                <a href="#about" class="text-gray-300 hover:text-white transition">About</a>
                <a href="#projects" class="text-gray-300 hover:text-white transition">Projects</a>
                <a href="#contact" class="text-gray-300 hover:text-white transition">Contact</a>
            </nav>
        </header>

        <!-- About Section -->
        <main>
            <section id="about" class="mb-16">
                <h2 class="text-3xl font-bold mb-4 gradient-text">About Me</h2>
                <p class="text-gray-300 leading-relaxed">
                    I am a passionate technologist with a keen interest in building scalable, secure, and resilient systems on the cloud. My journey involves mastering core infrastructure services on AWS and Azure, with a focus on automation, security-first design, and production-ready architecture. This portfolio itself is a testament to that, hosted securely and delivered globally using cloud-native services.
                </p>
            </section>

            <!-- Projects Section -->
            <section id="projects" class="mb-16">
                <h2 class="text-3xl font-bold mb-6 gradient-text">Cloud Projects</h2>
                <div class="grid grid-cols-1 md:grid-cols-2 gap-8">
                    <!-- Project 1 -->
                    <div class="bg-gray-800 rounded-lg p-6 shadow-lg hover:shadow-blue-500/20 transform hover:-translate-y-1 transition-all duration-300">
                        <h3 class="text-xl font-bold text-white mb-2">Secure Portfolio Website</h3>
                        <p class="text-gray-400 mb-4">This very website! Deployed on AWS S3 & Azure Blob, served via CDN with WAF protection. It's designed for high availability, low latency, and security.</p>
                        <div class="flex space-x-2">
                            <span class="bg-blue-900 text-blue-300 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded">AWS S3</span>
                            <span class="bg-blue-900 text-blue-300 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded">CloudFront</span>
                             <span class="bg-purple-900 text-purple-300 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded">Azure Blob</span>
                            <span class="bg-purple-900 text-purple-300 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded">Azure CDN</span>
                        </div>
                    </div>
                    <!-- Project 2 -->
                    <div class="bg-gray-800 rounded-lg p-6 shadow-lg hover:shadow-blue-500/20 transform hover:-translate-y-1 transition-all duration-300">
                        <h3 class="text-xl font-bold text-white mb-2">Automated Instance Scheduler</h3>
                        <p class="text-gray-400 mb-4">A serverless function that automatically stops/starts dev VMs to save costs, triggered on a schedule.</p>
                         <div class="flex space-x-2">
                            <span class="bg-blue-900 text-blue-300 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded">Lambda</span>
                            <span class="bg-purple-900 text-purple-300 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded">Azure Functions</span>
                        </div>
                    </div>
                </div>
            </section>

            <!-- Contact Section -->
            <section id="contact">
                <h2 class="text-3xl font-bold mb-4 gradient-text">Get In Touch</h2>
                <p class="text-gray-300 mb-6">Feel free to connect with me on professional networks.</p>
                <div class="flex space-x-4">
                    <a href="#" class="bg-gray-700 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded-lg transition-colors">LinkedIn</a>
                    <a href="#" class="bg-gray-700 hover:bg-gray-600 text-white font-bold py-2 px-4 rounded-lg transition-colors">GitHub</a>
                </div>
            </section>
        </main>

        <!-- Footer -->
        <footer class="text-center text-gray-500 mt-16">
            <p>&copy; <span id="year"></span> Your Name. All rights reserved.</p>
            <p>Built with <span class="text-red-400">&hearts;</span> and Cloud Native Services.</p>
        </footer>
    </div>

    <script>
        // Set current year in footer
        document.getElementById('year').textContent = new Date().getFullYear();
    </script>
</body>
</html>
AWS Tutorial

Step 2: Create a CloudFront Distribution (CDN)

The CDN will cache your website at edge locations worldwide, making it fast for all users and providing a place to attach our security layers.

  1. Navigate to CloudFront: Go to the CloudFront service in the console.
  2. Create Distribution: Click “Create a CloudFront distribution”.
  3. Origin Domain: In the “Origin domain” dropdown, select your S3 bucket.
  4. S3 bucket access (IMPORTANT):
    • Choose “Origin access control settings (recommended)”.
    • Click “Create control setting”. Keep the defaults and click “Create”.
    • A message will appear saying you need to update the S3 bucket policy. There will be a “Copy policy” button. Click it, we’ll use this in a moment.
  5. Viewer Protocol Policy: Under “Default cache behavior”, set “Viewer protocol policy” to “Redirect HTTP to HTTPS”. This enforces secure connections.
  6. Web Application Firewall (WAF): For now, select “Do not enable security protections”. We will add the WAF after the distribution is created, which is best practice.
  7. Default Root Object : Scroll down to the “Settings” section. In the “Default root object” field, enter index.html. This tells CloudFront to serve this file when a user visits the root URL.
  8. Create Distribution: Scroll down and click “Create distribution”. It will take about 5-10 minutes to deploy. While it’s deploying, you can proceed to the next step.
AWS Tutorial

Step 3: Secure the S3 Bucket

Now, we’ll apply the policy you copied to give CloudFront permission to read files from your private S3 bucket.

  1. Go back to S3: Navigate to your bucket.
  2. Permissions Tab: Click on the “Permissions” tab.
  3. Bucket Policy: Click “Edit” in the “Bucket policy” section.
  4. Paste Policy: Paste the JSON policy you copied from the CloudFront settings. It will look something like given below.
  5. Finally, Save changes. Your bucket is now private but accessible by CloudFront.
{
    "Version": "2008-10-17",
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Sid": "AllowCloudFrontServicePrincipal",
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudfront.amazonaws.com"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::your-bucket-name/*",
            "Condition": {
                "StringEquals": {
                    "AWS:SourceArn": "arn:aws:cloudfront::YOUR_AWS_ACCOUNT_ID:distribution/YOUR_CLOUDFRONT_DISTRIBUTION_ID"
                }
            }
        }
    ]
}

Step 4: Add the Web Application Firewall (WAF)

Finally, let’s add a layer of security.

  1. Navigate to WAF & Shield: Go to the service in the AWS Console.
  2. Create Web ACL:
    • Resource type: CloudFront distribution.
    • Name: portfolio-waf.
    • Click “Add AWS managed rule groups”.
    • Add the “Core rule set” and “Known bad inputs rule set”. These protect against the most common attacks like SQL injection and XSS.
    • Set the default action to “Allow”.
    • In the next step, associate it with your CloudFront distribution.
    • Review and create the Web ACL.

Step 5: Access Your Website

You’re all set! Once your CloudFront distribution’s status changes from “Deploying” to “Enabled”, you can access your site.

  1. Navigate to your CloudFront distribution in the AWS console.
  2. In the list of distributions, find the “Domain name” column. It will show a URL like d123abcdef.cloudfront.net.
  3. Copy this URL and paste it into your browser. Your secure, fast, and professional portfolio website will be live!

Build Portfolio Website Using Azure Services

Services Used

  • Storage Account
  • Azure Front Door (CDN + WAF)

Step 1: Create a Storage Account

This is Azure’s equivalent of S3 and will hold your website files.

  1. Navigate to Storage Accounts: In the Azure Portal, search for and select “Storage accounts”.
  2. Create: Click “Create”.
    • Subscription/Resource Group: Select your subscription and create a new resource group (e.g., portfolio-rg).
    • Storage account name: Give it a unique, lowercase name (e.g., yournameportfoliosource).
    • Region: Choose a region.
    • Performance/Redundancy: Standard / GRS is fine.
  3. Review and Create: Click “Review + create”, then “Create”.
  4. Enable Static Website:
    • Once deployed, go to the storage account.
    • In the left menu under “Data management”, click “Static website”.
    • Toggle it to Enabled.
    • Enter index.html as the “Index document name”.
    • Click Save. This creates a special container called $web.
  5. Upload Files: Navigate to “Containers” in the left menu, click on the $web container, and upload your index.html file and other assets. (use the sample html code provided in AWS part)
Website using Azure
Website using Azure
Website using Azure

Step 2: Create Azure Front Door (CDN + WAF)

This single service will handle content delivery, the SSL certificate, and security.

  1. Search for Azure Front Door: In the portal, search for and select “Front Door and CDN profiles”.
  2. Create: Click “Create”.
  3. Compare offerings: Select “Azure Front Door” and click “Continue”.
  4. Quick Create:
    • Resource Group: Select the one you created earlier.
    • Name: Give it a name (e.g., portfolio-frontdoor).
    • Tier: Standard is sufficient.
    • Endpoint name: This will be part of your public URL (e.g., yourname-portfolio). The full URL will look like yourname-portfolio.z01.azurefd.net. Make a note of this hostname.
    • Origin type: Select “Storage (static website)”.
    • Origin host name: Select your storage account from the dropdown.
  5. WAF Policy: Click “Create new” to add a security policy.
    • Name: portfolio-waf-policy.
    • Click “Create”.
  6. Review and Create: Click “Review + create”, then “Create”. Deployment can take 5-10 minutes.
Website using Azure

Step 3: Secure the Storage Account (IMPORTANT)

This is the final, critical step to ensure no one can bypass your WAF and CDN.

  1. Navigate to your Storage Account.
  2. Networking: In the left menu under “Security + networking”, click “Networking”.
  3. Public network access: Under the “Public network access” tab, select “Enabled from selected virtual networks and IP addresses”.
  4. Save: Click “Save” at the top.

This firewall rule ensures that the only service in the world that can access your storage account is your specific Azure Front Door instance.

Website using Azure

Step 4: Access Your Website

You’re all set! There’s no need to configure DNS.

  1. Navigate to your Azure Front Door profile in the Azure portal.
  2. On the Overview page, find the “Endpoint hostname”. It will be a URL like https://yourname-portfolio.z01.azurefd.net.
  3. Copy this URL and paste it into your browser. Your secure, Azure-hosted portfolio will be live!