Skip to content

Website securing and hosting with CGP and Cloudflare + Personal wedding website stuff

Notifications You must be signed in to change notification settings

TdjHJ9zM5k/website-hosting-securing

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

56 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

My wedding website repo + Website securing and hosting guide


Table of Contents

  1. Overview
  2. Features
  3. Prerequisites
  4. Google Cloud Platform (GCP) Setup
  5. Cloudflare Setup
  6. HTML Files for Wix website encapsulation
  7. Bonus - Weather APIs

Overview

This guide demonstrates how to:

  1. Set up a custom domain and configure DNS.
  2. Set up a static website with Google Cloud Storage that will be reached via a custom domain.
  3. Host your site using Google Cloud Storage.
  4. Configure SSL, Namespace and Firewall through Cloudflare.
  5. iframe manipulation
  6. Implement APIs in Wix Velo

The guide is intended for techincal and non-technical audience. Steps requiring more in-depth knoledge are marked with a ✬ symbol.


Features

  • Custom Domain Integration
    Connect your domain to your Wix site by hosting a static website on Google Cloud Storage Bucket.

  • Static Hosting
    Use Google Cloud Storage as a static website host.

  • Secure Website
    Implement HTTPS and WAF with Cloudflare.


Prerequisites

To use this guide, you'll need:

  • A registered domain name.
  • Access to Google Cloud Platform (GCP).
  • A Cloudflare account.
  • Basic understanding of DNS and hosting.

Step-by-Step Guide

Domain Registration

  • Purchase and register a domain. Namecheap or GoDaddy are usually suggested.

GCP Static Website Setup

GCP Configuration

  1. Register domain ownership

    • We need to create a Google Cloud Storage instance with the same name as our website. In order to do this, we need to prove Google we own the domain by adding a record to our DNS.
    • Visit Google Search Console
    • Fill in your domain name under the Domain section.
    • Click CONTINUE and then select CNAME as verification method.
    • Add a CNAME record to your DNS with the provided data.
  2. Set up a GCP project

  3. Set up a GCP bucket for hosting

    • An official Google documentation page can be accessed at Hosting a static website using HTTP. Our procedure will differ in how public access is granted to each file.

    • Use the same name as the registered domain with the format www.my-domain.com.

    • For our private-use, research-purpose project, we select a single region, like us-central1.

    • Deselect Enforce public access prevention on this bucket as we will be granting our file public access.

      First Bucket Creation

    • Additional but not required: Create a storage acting as a backup with the NEARLINE storage class for reducing costs and set up a replication policy.

      Backup Bucket Creation

    • ✬ Equivalent gcloud commands:

       # Set the project name
       PROJECT_ID=<YOUR_PROJECT_ID>
       
       # Set the main bucket
       MAIN_BUCKET_NAME="www.my-domain.com" #Change it to your registered domain
      
       # Set the bucket zone
       BUCKET_ZONE="us-central1"
       
       # Dynamically create the backup bucket name
       BACKUP_BUCKET_NAME="backup-${MAIN_BUCKET_NAME}"
       
       # Dynamically get the project ID
       PROJECT_NUMBER=$(gcloud projects describe "$PROJECT_ID" --format="value(projectNumber)")
       
       # Set the active project
       gcloud config set project "$PROJECT_ID"
       
       # Create the main bucket
       gcloud storage buckets create "gs://${MAIN_BUCKET_NAME}" \
         --location=${BUCKET_ZONE} \
         --default-storage-class=STANDARD \
         --no-public-access-prevention \
         --no-uniform-bucket-level-access
       
       # Configure access to use index.html as the main page
       gcloud storage buckets update "gs://${MAIN_BUCKET_NAME}" --web-main-page-suffix=index.html
       
       # Create the backup bucket
       gcloud storage buckets create "gs://${BACKUP_BUCKET_NAME}" \
         --location=${BUCKET_ZONE} \
         --default-storage-class=NEARLINE \
         --public-access-prevention \
         --uniform-bucket-level-access
       
       # Enable the Storage Transfer Service API
       gcloud services enable storagetransfer.googleapis.com
       
       # Set up IAM roles for data transfer
       TRANSFER_SERVICE_ACCOUNT="project-${PROJECT_NUMBER}@storage-transfer-service.iam.gserviceaccount.com"
       STORAGE_SERVICE_ACCOUNT="service-${PROJECT_NUMBER}@gs-project-accounts.iam.gserviceaccount.com"
       
       # Grant IAM roles for the main bucket
       gcloud storage buckets add-iam-policy-binding "gs://${MAIN_BUCKET_NAME}" \
         --member="serviceAccount:${TRANSFER_SERVICE_ACCOUNT}" \
         --role="roles/storage.admin"
       
       # Grant IAM roles to the project for data transfer
       gcloud projects add-iam-policy-binding "$PROJECT_NUMBER" \
         --member="serviceAccount:${TRANSFER_SERVICE_ACCOUNT}" \
         --role="roles/storage.admin"
       
       gcloud projects add-iam-policy-binding "$PROJECT_NUMBER" \
         --member="serviceAccount:${TRANSFER_SERVICE_ACCOUNT}" \
         --role="roles/pubsub.editor"
       
       # Grant IAM roles to the Cloud Storage service account
       gcloud projects add-iam-policy-binding "$PROJECT_NUMBER" \
         --member="serviceAccount:${STORAGE_SERVICE_ACCOUNT}" \
         --role="roles/pubsub.publisher"
       
       # Create the replication job
       gcloud alpha transfer jobs create "gs://${MAIN_BUCKET_NAME}" "gs://${BACKUP_BUCKET_NAME}" --replication
       
       # List active replication jobs
       gcloud alpha transfer jobs list --job-type=replication
    • ✬ A Terraform equivalent, including the index.html and mobile.html creation, can be found at main.tf.


Cloudflare Setup

Overview

This section covers the configuration of HTTPS, DNS, nameservers, and Web Application Firewall (WAF) rules using Cloudflare. The goal is to secure your static website hosted on Google Cloud Platform (GCP) and ensure proper traffic handling.

Prerequisites

  • A Cloudflare account.
  • The domain name registered and added to your Cloudflare account.
  • Access to the DNS management settings in your registrar's dashboard.
  1. Add Your Domain to Cloudflare

    • Log in to your Cloudflare account.
    • Click on Add a Site and enter your domain name (e.g., my-domain.com).
    • Cloudflare will scan your existing DNS records. Verify them and make necessary adjustments.
  2. Set Up DNS Records

    • Add a CNAME record pointing from www.my-domain.com to the GCP bucket hosting your static website:

      Name Type Content TTL
      www CNAME c.storage.googleapis.com Auto
      • Import file alternative (change content with your domain name)
      • ✬ CLI alternative (using Cloudflare API):
        curl -X POST "https://api.cloudflare.com/client/v4/zones/<ZONE_ID>/dns_records" \
        -H "Authorization: Bearer <API_TOKEN>" \
        -H "Content-Type: application/json" \
        --data '{
          "type":"CNAME",
          "name":"www.my-domain.com",
          "content":"c.storage.googleapis.com",
          "ttl":1,
          "proxied":true
        }'
  3. Change Nameservers

    • Cloudflare will provide two nameservers (e.g., ns1.cloudflare.com and ns2.cloudflare.com) under the page DNS/Records.
    • Update your registrar's DNS settings to point to these nameservers. This change may take up to 48 hours to propagate.
  4. Enable HTTPS

    • In Cloudflare's SSL/TLS section, set the mode to Full or Full (strict) for secure communication.
    • Toggle Always Use HTTPS to automatically redirect HTTP traffic to HTTPS.
  5. Add Redirect Rules

    • Go to the Rules section and create the following redirects:
      • Redirect HTTP to HTTPS
        Match: http://*/*
        Redirect to: https://$1/$2
        (Enable "Forwarding URL")

      • Redirect Root HTTPS to WWW
        Match: https://my-domain.com/*
        Redirect to: https://www.my-domain.com/$1
        (Enable "Forwarding URL")

Configure Cloudflare WAF Rules

  1. Restrict Traffic to Specific Countries

    • Rule: Allow traffic only from specified country.
    • Expression example:
      not ip.geoip.country in {"GB" "US" "DE"}
      
  2. Block Access to Unwanted Pages

    • Rule: Block all pages except the allowed ones.
    • Expression:
      not ends_with(http.request.full_uri, "/") and
      not ends_with(http.request.full_uri, "/favicon.ico") and
      not ends_with(http.request.full_uri, "/mobile.html")
      
  3. Block Suspicious User Agents

    • Rule: Block bots, crawlers, and headless browsers.
    • Expression:
      (http.user_agent contains "bot") or 
      (http.user_agent contains "crawl") or 
      (http.user_agent contains "spider") or 
      (http.user_agent contains "Headless") or 
      (not ssl)
      
  4. Block Based on Threat Score

    • Rule: Block if threat_score >= 1
    • Expression:
      cf.threat_score ge 1
      
  5. Block Known Bots

    • Rule: Block all known bots.
    • Enable the "Known Bots" option in Cloudflare WAF.

Test the Configuration

  • Verify that www.my-domain.com resolves correctly and loads your static website.
  • Ensure HTTPS is enforced and all redirects work as expected.
  • Test the WAF rules using different countries, user agents, and URLs.

This setup ensures secure and optimized traffic handling for your custom domain, leveraging Cloudflare's powerful tools to enhance the functionality and security of your site.


HTML Files for Wix website encapsulation

Overview

This section presents the two index.html and mobile.html files. The index.html is pretty straightforward, it contains a shifted iframe pointing at the wix webiste and a redirect to mobile.html when the screen with is less then 900px.

The mobile.html is a bit more complex as Wix forces a 320px width that results in a non-responsive resizing. This is addressed through zooming in/out the iframe as screen sizes changes.

Note: I implemented the zooming feature using some help from AI, it may be enhanced more

The files

  1. index.html

    • switch Wix url with your actual Wix website url
    • select a custom title

          <!DOCTYPE html>
          <html lang="it">
             <head>
               <meta charset="UTF-8">
               <meta name="viewport" content="width=device-width, initial-scale=1.0">
               <title>My title</title>
               <link rel="icon" href="https://storage.googleapis.com/www.my-website.com/favicon.ico" type="image/x-icon">
             </head>
            
             <body>
               <iframe src="https://my.wixsite.com/" style="position:fixed; top:-50px; left:0px; bottom:0px; right:0px; width:100%; height:105%; ">
               </iframe>  
             
               <script type="text/javascript">
                 if (screen.width <= 900) {
                   document.location = "/mobile.html";
                 }
               </script>
               
             </body>
          </html>
  2. mobile.html

    • switch Wix url with your actual Wix website url
    • select a custom title

       <!DOCTYPE html>
       <html lang="it">
            <head>
               <meta charset="UTF-8">
               <title>My title</title>
               <link rel="icon" href="https://storage.googleapis.com/www.my-website.com/favicon.ico" type="image/x-icon">
               <meta name="theme-color" content="#6E1633">
               <meta name="viewport" content="width=device-width, initial-scale=1.0">
            
               <style>
                 /* Hide only the Wix ad banner */
                 iframe {
                   position: fixed;
                   left: 0;
                   top: -39px; /* Adjust as needed to hide the banner */
                   width: 100%;
                   height: calc(100% + 39px); /* Adjusted to cover the area hidden by the banner */
                   border: none;
                 }
                 /* Remove any padding and margin */
                 body {
                   margin: 0;
                   padding: 0;
                   background-color:#E9CAB1;
                 }
               </style>
            </head>
            <body>
            
              <iframe src="https://my.wixsite.com/" style="position: fixed;    left: 0px;    top: -39px;    width: 100%;    height: 108%;">
              </iframe>  
              <script>
                function resizeIframe() {
                  const iframe = document.querySelector('iframe');
                  const screenWidth = window.innerWidth;
                  const screenHeight = window.innerHeight;
          
                  // Define the base width and top offset of the Wix content
                  const baseWidth = 320; // Original width of the Wix content
                  const baseTop = -39;   // Original `top` offset
                  const scaleFactor = screenWidth / baseWidth;
          
                  // Apply scaling to the iframe
                  iframe.style.transform = `scale(${scaleFactor})`;
                  iframe.style.transformOrigin = "top left";
          
                  // Adjust iframe's dimensions and position
                  iframe.style.width = `${baseWidth}px`; // Original content width
                  const newHeight = (screenHeight / scaleFactor) - (baseTop * scaleFactor); // Compensate for banner removal
                  iframe.style.height = `${newHeight}px`; // Scaled height to fit the viewport
                  iframe.style.left = `calc((100vw - ${baseWidth}px * ${scaleFactor}) / 2)`; // Center horizontally
                  iframe.style.top = `${baseTop * scaleFactor}px`; // Scale the top offset
                }
          
                // Run resize function immediately after DOM is loaded
                document.addEventListener('DOMContentLoaded', resizeIframe);
          
                // Resize on window resize events (debounced for better performance)
                let resizeTimeout;
                window.addEventListener('resize', () => {
                  clearTimeout(resizeTimeout);
                  resizeTimeout = setTimeout(resizeIframe, 100);
                });
              </script>
            </body>
       </html>
  3. favicon.ico

    • you can upload a custom favicon.ico to the bucket and reference it into index.html and mobile.html

Bonus Weather APIs

An implementation of The Norwegian Meteorological Institute Weather API can be found in /velo/weather.js. It is leveraged to present a weather widget.


visitors

About

Website securing and hosting with CGP and Cloudflare + Personal wedding website stuff

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published