← Back to Main Page

How Do I Deploy My Website

Website Architecture Diagram

This website is hosted using a combination of AWS services such as S3, CloudFront, API Gateway, Lambda, DynamoDB, ACM, Cloudwatch, SNS, and Cloudflare DNS. Terraform is used to automate the infrastructure provisioning, and GitLab CI/CD automates the deployment process. I do use Route53 Health Check with Cloudwatch alert for making sure my URL is UP. Below is an overview of the deployment process:

1. GitLab CI/CD for Automated Deployments

GitLab CI/CD

The deployment process is managed through a GitLab CI/CD pipeline that handles both development and production environments:

Development Pipeline (dev branch):

  • Build Stage:
    • Uses Docker-Compose service for container builds
    • Builds a development Docker image using a custom Dockerfile
    • Runs only on the 'dev' branch
  • Deploy Stage:
    • Deploys the application using Docker-Compose
    • Provides containerized development environment
    • Automatically rebuilds and updates service

Production Pipeline (main branch):

  • Deploy Stage:
    • Authenticates with AWS using secure credentials
    • Synchronizes content with S3 bucket (sahibgasimov.com)
    • Automatically invalidates CloudFront cache makes sure content updates immediately
    • Runs only on the 'main' branch for production deployments

GitLab CI/CD

2. Terraform for Infrastructure as Code

In this setup Terraform I use to provision and manage AWS resources only. I keep IaC consistent which allows version control for the entire environment configuration.

3. S3 as an Origin for CloudFront

The website's static files (HTML, CSS, JavaScript) are stored in an S3 bucket configured as a private origin for CloudFront. Public access to the S3 bucket is disabled, and an Origin Access Control (OAC) is used to securely grant CloudFront permission to access the bucket. All content delivery is managed through CloudFront for enhanced caching, compression, and global delivery.

4. CloudFront CDN for Fast and Secure Content Delivery

CloudFront is configured as the primary CDN for the website, ensuring fast, secure, and efficient content delivery. Below are the key technical enhancements made to the CloudFront setup:

  • Caching Optimization:
    • The CachingOptimized policy has been applied to enable efficient caching of frequently accessed files.
    • TTL (Time-to-Live) values for content have been fine-tuned to balance performance and content freshness:
      • DefaultTTL: 86400 seconds (1 day)
      • MaxTTL: 31536000 seconds (1 year)
      • MinTTL: 0 seconds (allows dynamic adjustments)
    • Object cache control is managed using metadata on the S3 origin (e.g., Cache-Control headers).
  • Compression: Brotli and Gzip compression are enabled, ensuring reduced payload sizes for faster delivery of assets such as HTML, CSS, and JavaScript.
  • Security Enhancements:
    • HTTP-to-HTTPS redirection is enforced using the ViewerProtocolPolicy set to redirect-to-https.
    • Key HTTP security headers are added using a custom response headers policy:
      • Strict-Transport-Security: Forces HTTPS connections with a max-age of 1 year.
      • X-Content-Type-Options: Prevents MIME type sniffing.
      • X-Frame-Options: Set to SAMEORIGIN, mitigating clickjacking attacks.
      • Referrer-Policy: Set to no-referrer, enhancing privacy.
  • Origin Access Control (OAC):
    • The S3 bucket used as the CloudFront origin is configured with an OAC to block all public access and only allow CloudFront to fetch content securely.
    • This ensures the bucket cannot be accessed directly, improving security and centralizing content delivery through CloudFront.
  • Clean URL Management: A custom CloudFront Function is implemented to handle URL path rewriting:
    • URLs ending with .html (e.g., /about.html) are redirected to paths without the extension (e.g., /about).
    • Paths without extensions automatically append .html (e.g., /about becomes /about.html).

Additionally, I'm using a CloudFront Function for HTML path redirection. All it does is cut ".html" from the file endings. For example, if I have about.html, I can now route the path to /about, and .html won't appear even if the user specifies .html explicitly. I've provided detailed step-by-step instructions for this setup in my Medium blog.

CloudFront Function Code:


function handler(event) {
  var request = event.request;
  var uri = request.uri;

  // Check if the URI ends with .html
  if (uri.endsWith('.html')) {
    // Redirect to the version without .html (e.g., /about.html -> /about)
    var newUri = uri.slice(0, -5); // Remove ".html" from the end of the URI

    return {
      statusCode: 301,
      statusDescription: 'Moved Permanently',
      headers: {
        'location': { 'value': newUri }
      }
    };
  }

  // Append .html if the URI does not have an extension or does not end with a slash
  if (!uri.includes('.') && !uri.endsWith('/')) {
    request.uri += '.html'; // Append .html to paths without extensions
  }

  // Return the modified request
  return request;
}

5. API Gateway and Lambda (Python) for Dynamic Functionality

API Gateway is used to expose endpoints (e.g., getCount and updateCount) that trigger Lambda functions written in Python. These Lambda functions interact with a DynamoDB table to perform operations such as retrieving and updating data. The Lambda functions are assigned an IAM role for secure access to DynamoDB using boto3 API calls.

6. DynamoDB for Data Storage

A DynamoDB table is used to store the hit count. The visitor counter needed to retrieve and update its count in a database.

7. CloudWatch and Route53 for Monitoring and Alerts

CloudWatch is configured to monitor the health of Route53 Health Check URL path, and trigger alarms via SNS notifications.

8. SNS for Notifications

In the event of operational issues or threshold breaches, CloudWatch triggers alarms that notify the admin via an SNS topic, ensuring timely responses to any issues.

9. Cloudflare for DNS

My DNS is stored in Cloudflare. I manage a couple of websites, and being able to control DNS from a single dashboard without needing their password for their domain registrar is nice when I move or change the server I am hosting them on I also have a homelab, so instead of exposing ports on my router to various hosted services, I create subdomains for a domain I own and then follow this policy: If access to the service is public (like a website) I use a Cloudflare Tunnel. I can set access rules to block or allow certain countries, etc. If access to the service is restricted to me and a few other users, I use a Cloudflare Tunnel and a Cloudflare Application to provide authentication.

10. Frontend Development with HTML, CSS, and JavaScript

The front-end of the website is built using classic HTML for structure, CSS for styling, and JavaScript for interactivity. This ensures a responsive and dynamic user experience across different devices and browsers.