The Scripts

The automation behind F5G.pro

Scripts

Explore the scripts that power F5G.pro with this GitHub-inspired file browser.

setup-all.sh

This is the main script that orchestrates the entire setup process.

#!/bin/bash

# Exit on error
set -e

echo "๐Ÿš€ Starting F5G.pro infrastructure setup..."

# Make scripts executable
chmod +x scripts/*.sh

# Run setup scripts in order
./scripts/setup-s3.sh
echo ""
./scripts/setup-iam.sh
echo ""
./scripts/setup-cloudfront.sh

echo ""
echo "๐ŸŽ‰ Setup complete!"
echo ""
echo "๐Ÿ“ Next steps:"
echo "1. Add the following secrets to your GitHub repository:"
echo "   - AWS_ACCESS_KEY_ID"
echo "   - AWS_SECRET_ACCESS_KEY"
echo "   - S3_BUCKET (set to 'f5g.pro')"
echo "   - CLOUDFRONT_DISTRIBUTION_ID"
echo ""
echo "2. Set up your DNS records to point to your CloudFront distribution"
echo "3. Push your code to GitHub to trigger the first deployment" 

fix-cloudfront-cache.sh

This script fixes caching issues by enabling compression and updating the cache policy to include query parameters.

#!/bin/bash

# Exit on error
set -e

echo "โ˜๏ธ Updating CloudFront distribution to fix caching issues..."

# Get the distribution ID
DISTRIBUTION_ID=$(aws cloudfront list-distributions --query "DistributionList.Items[?Origins.Items[0].DomainName=='f5g.pro.s3.amazonaws.com'].Id" --output text)

if [ -z "$DISTRIBUTION_ID" ]; then
    echo "โŒ Error: CloudFront distribution for f5g.pro not found!"
    exit 1
fi

echo "๐Ÿ” Found CloudFront distribution with ID: $DISTRIBUTION_ID"

# Get the current distribution configuration
echo "๐Ÿ“ฅ Retrieving current configuration..."
aws cloudfront get-distribution-config --id $DISTRIBUTION_ID --output json > distribution-config-old.json

# Extract the ETag value (needed for update)
ETAG=$(grep -o '"ETag"[[:space:]]*:[[:space:]]*"[^"]*"' distribution-config-old.json | sed 's/"ETag"[[:space:]]*:[[:space:]]*"\([^"]*\)"/\1/')

# Extract just the DistributionConfig portion
jq '.DistributionConfig' distribution-config-old.json > distribution-config-extracted.json

# Enable compression
jq '.DefaultCacheBehavior.Compress = true' distribution-config-extracted.json > distribution-config-compression.json

# Change cache policy to "CachingOptimizedForUncompressedObjects" which includes query strings
# Policy ID: b2884449-e4de-46a7-ac36-70bc7f1ddd6d
jq '.DefaultCacheBehavior.CachePolicyId = "b2884449-e4de-46a7-ac36-70bc7f1ddd6d"' distribution-config-compression.json > distribution-config-new.json

echo "๐Ÿ”„ Updating distribution with fixed caching settings..."
aws cloudfront update-distribution --id $DISTRIBUTION_ID --if-match $ETAG --distribution-config file://distribution-config-new.json > /dev/null

echo "๐Ÿงน Cleaning up temporary files..."
rm distribution-config-old.json distribution-config-extracted.json distribution-config-compression.json distribution-config-new.json

echo "โœ… CloudFront distribution updated with optimal caching settings!"
echo "โฑ๏ธ It may take up to 15-30 minutes for the changes to propagate across all edge locations."
echo "๐ŸŒ After the propagation is complete, your content will be properly cached by CloudFront."
echo "๐Ÿ“ The changes made:"
echo "  - Enabled compression"
echo "  - Changed cache policy to include query strings in the cache key"
echo "  - This ensures cache busting with query parameters works correctly"

invalidate-cloudfront-cache.sh

This script invalidates the CloudFront cache after deployments.

#!/bin/bash

# Exit on error
set -e

echo "โ˜๏ธ Invalidating CloudFront distribution cache..."

# Get the distribution ID
DISTRIBUTION_ID=$(aws cloudfront list-distributions --query "DistributionList.Items[?Origins.Items[0].DomainName=='f5g.pro.s3.amazonaws.com'].Id" --output text)

if [ -z "$DISTRIBUTION_ID" ]; then
    echo "โŒ Error: CloudFront distribution for f5g.pro not found!"
    exit 1
fi

echo "๐Ÿ” Found CloudFront distribution with ID: $DISTRIBUTION_ID"

# Create a timestamp for the reference ID
TIMESTAMP=$(date +%Y%m%d%H%M%S)

# Paths to invalidate - '/*' invalidates everything
PATHS_TO_INVALIDATE='/*'

echo "๐Ÿ”„ Creating cache invalidation for paths: $PATHS_TO_INVALIDATE"
INVALIDATION_ID=$(aws cloudfront create-invalidation \
    --distribution-id $DISTRIBUTION_ID \
    --paths "$PATHS_TO_INVALIDATE" \
    --caller-reference "deploy-$TIMESTAMP" \
    --query 'Invalidation.Id' \
    --output text)

echo "โœ… Invalidation created with ID: $INVALIDATION_ID"
echo "โฑ๏ธ Invalidation in progress. This may take 5-15 minutes to complete across all edge locations."
echo "๐ŸŒ After the invalidation is complete, all users will see the latest version of your website."

setup-cloudfront.sh

This script creates and configures the CloudFront distribution for the website.

#!/bin/bash

# Exit on error
set -e

echo "โ˜๏ธ Setting up CloudFront distribution..."

# Check if distribution already exists for f5g.pro
EXISTING_DIST_ID=$(aws cloudfront list-distributions --query "DistributionList.Items[?Origins.Items[0].DomainName=='f5g.pro.s3.amazonaws.com'].Id" --output text)

if [ ! -z "$EXISTING_DIST_ID" ]; then
    echo "โ˜๏ธ CloudFront distribution already exists with ID: $EXISTING_DIST_ID"
    DISTRIBUTION_ID=$EXISTING_DIST_ID
else
    # Create a temporary JSON file for the distribution config
    cat > distribution-config.json << EOF
{
    "CallerReference": "$(date +%s)",
    "Origins": {
        "Quantity": 1,
        "Items": [
            {
                "Id": "S3-f5g.pro",
                "DomainName": "f5g.pro.s3.amazonaws.com",
                "S3OriginConfig": {
                    "OriginAccessIdentity": ""
                }
            }
        ]
    },
    "DefaultCacheBehavior": {
        "TargetOriginId": "S3-f5g.pro",
        "ViewerProtocolPolicy": "redirect-to-https",
        "CachePolicyId": "4135ea2d-6df8-44a3-9df3-4b5a84be39ad",
        "AllowedMethods": {
            "Quantity": 2,
            "Items": ["HEAD", "GET"],
            "CachedMethods": {
                "Quantity": 2,
                "Items": ["HEAD", "GET"]
            }
        }
    },
    "Comment": "F5G.pro website distribution",
    "Enabled": true,
    "DefaultRootObject": "index.html"
}
EOF

    # Create CloudFront distribution
    echo "๐Ÿš€ Creating CloudFront distribution..."
    DISTRIBUTION_ID=$(aws cloudfront create-distribution \
        --distribution-config file://distribution-config.json \
        --query 'Distribution.Id' \
        --output text)

    # Clean up the temporary file
    rm distribution-config.json
fi

echo "โœ… CloudFront distribution ID: $DISTRIBUTION_ID"
echo "๐Ÿ“ Please save this Distribution ID for your GitHub secret CLOUDFRONT_DISTRIBUTION_ID"

# Get and display the distribution domain name
DOMAIN_NAME=$(aws cloudfront get-distribution --id $DISTRIBUTION_ID --query 'Distribution.DomainName' --output text)
echo "๐ŸŒ CloudFront Domain Name: $DOMAIN_NAME"
echo "๐Ÿ“ Update your DNS records to point f5g.pro to this domain name" 

setup-counter.sh

This script sets up a visitor counter using S3, Lambda, and API Gateway.

#!/bin/bash

# Exit on error
set -e

echo "๐Ÿ”ข Setting up visitor counter for f5g.pro..."

# Define variables
BUCKET_NAME="f5g.pro"
COUNTER_FILE="counter.json"
LAMBDA_FUNCTION_NAME="f5gVisitorCounter"
API_NAME="F5GCounterAPI"
API_STAGE="prod"
REGION="us-east-1"
LAMBDA_SOURCE="/Users/myleshenderson/src/f5g/lambda/visitor-counter.js"

# Check if counter file exists
echo "๐Ÿ“Š Checking if counter file exists..."
if aws s3api head-object --bucket "$BUCKET_NAME" --key "$COUNTER_FILE" >/dev/null 2>&1; then
    echo "๐Ÿ“Š Counter file already exists"
else
    echo "๐Ÿ“Š Creating counter file in S3..."
    echo '{"count": 0}' > /tmp/counter.json
    aws s3 cp /tmp/counter.json "s3://$BUCKET_NAME/$COUNTER_FILE"
    rm /tmp/counter.json
fi

# Check if IAM role exists
ROLE_NAME="F5GCounterLambdaRole"
echo "๐Ÿ‘ค Checking if IAM role exists..."
if aws iam get-role --role-name "$ROLE_NAME" >/dev/null 2>&1; then
    echo "๐Ÿ‘ค Role $ROLE_NAME already exists"
    ROLE_ARN=$(aws iam get-role --role-name "$ROLE_NAME" --query "Role.Arn" --output text)
else
    echo "๐Ÿ‘ค Creating IAM role..."
    # Create trust policy document
    cat > /tmp/trust-policy.json <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
EOF

    # Create role
    ROLE_ARN=$(aws iam create-role --role-name "$ROLE_NAME" --assume-role-policy-document file:///tmp/trust-policy.json --query "Role.Arn" --output text)
    
    # Create policy document for S3 access
    cat > /tmp/s3-policy.json <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject"
      ],
      "Resource": "arn:aws:s3:::$BUCKET_NAME/$COUNTER_FILE"
    },
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "arn:aws:logs:*:*:*"
    }
  ]
}
EOF

    # Create and attach policy
    POLICY_NAME="F5GCounterS3Access"
    POLICY_ARN=$(aws iam create-policy --policy-name "$POLICY_NAME" --policy-document file:///tmp/s3-policy.json --query "Policy.Arn" --output text)
    aws iam attach-role-policy --role-name "$ROLE_NAME" --policy-arn "$POLICY_ARN"
    
    # Cleanup temp files
    rm /tmp/trust-policy.json /tmp/s3-policy.json
    
    # Wait for IAM role propagation
    echo "โณ Waiting for IAM role propagation..."
    sleep 10
fi

# Check if Lambda function exists and create/update as needed
echo "ฮป๏ธ Checking Lambda function..."
if aws lambda get-function --function-name "$LAMBDA_FUNCTION_NAME" >/dev/null 2>&1; then
    echo "ฮป๏ธ Lambda function $LAMBDA_FUNCTION_NAME exists, updating code..."
    
    # Create temp directory for zip
    mkdir -p /tmp/lambda
    cp "$LAMBDA_SOURCE" /tmp/lambda/index.js
    
    # Install AWS SDK dependencies
    cd /tmp/lambda
    npm init -y >/dev/null 2>&1
    npm install @aws-sdk/client-s3 --save >/dev/null 2>&1
    
    # Create zip file
    zip -r function.zip index.js node_modules >/dev/null
    
    # Update Lambda function code
    aws lambda update-function-code \
      --function-name "$LAMBDA_FUNCTION_NAME" \
      --zip-file fileb://function.zip
    
    # Update environment variables
    aws lambda update-function-configuration \
      --function-name "$LAMBDA_FUNCTION_NAME" \
      --environment "Variables={BUCKET_NAME=$BUCKET_NAME,COUNTER_FILE=$COUNTER_FILE}"
    
    # Cleanup
    cd -
    rm -rf /tmp/lambda
else
    echo "ฮป๏ธ Creating Lambda function..."
    
    # Create temp directory for zip
    mkdir -p /tmp/lambda
    cp "$LAMBDA_SOURCE" /tmp/lambda/index.js
    
    # Install AWS SDK dependencies
    cd /tmp/lambda
    npm init -y >/dev/null 2>&1
    npm install @aws-sdk/client-s3 --save >/dev/null 2>&1
    
    # Create zip file
    zip -r function.zip index.js node_modules >/dev/null
    
    # Create Lambda function
    aws lambda create-function \
      --function-name "$LAMBDA_FUNCTION_NAME" \
      --runtime nodejs18.x \
      --role "$ROLE_ARN" \
      --handler index.handler \
      --zip-file fileb://function.zip \
      --environment "Variables={BUCKET_NAME=$BUCKET_NAME,COUNTER_FILE=$COUNTER_FILE}"
    
    # Cleanup
    cd -
    rm -rf /tmp/lambda
fi

# Check if API Gateway exists
echo "๐ŸŒ Checking if API Gateway exists..."
API_ID=$(aws apigateway get-rest-apis --query "items[?name=='$API_NAME'].id" --output text)
if [ -n "$API_ID" ]; then
    echo "๐ŸŒ API Gateway $API_NAME already exists with ID: $API_ID"
else
    echo "๐ŸŒ Creating API Gateway..."
    API_ID=$(aws apigateway create-rest-api --name "$API_NAME" --query "id" --output text)
    ROOT_RESOURCE_ID=$(aws apigateway get-resources --rest-api-id "$API_ID" --query "items[0].id" --output text)

    # Create a resource
    echo "๐ŸŒ Creating API resource..."
    RESOURCE_ID=$(aws apigateway create-resource --rest-api-id "$API_ID" --parent-id "$ROOT_RESOURCE_ID" --path-part "increment" --query "id" --output text)

    # Create method
    echo "๐ŸŒ Creating API method..."
    aws apigateway put-method --rest-api-id "$API_ID" --resource-id "$RESOURCE_ID" --http-method GET --authorization-type NONE

    # Set Lambda integration
    echo "๐ŸŒ Setting up Lambda integration..."
    LAMBDA_ARN="arn:aws:lambda:$REGION:$(aws sts get-caller-identity --query Account --output text):function:$LAMBDA_FUNCTION_NAME"
    aws apigateway put-integration \
      --rest-api-id "$API_ID" \
      --resource-id "$RESOURCE_ID" \
      --http-method GET \
      --type AWS_PROXY \
      --integration-http-method POST \
      --uri "arn:aws:apigateway:$REGION:lambda:path/2015-03-31/functions/$LAMBDA_ARN/invocations"

    # Deploy API
    echo "๐ŸŒ Deploying API..."
    aws apigateway create-deployment --rest-api-id "$API_ID" --stage-name "$API_STAGE"

    # Set Lambda permission for API Gateway
    echo "ฮป๏ธ Setting Lambda permissions for API Gateway..."
    aws lambda add-permission \
      --function-name "$LAMBDA_FUNCTION_NAME" \
      --statement-id apigateway \
      --action lambda:InvokeFunction \
      --principal apigateway.amazonaws.com \
      --source-arn "arn:aws:execute-api:$REGION:$(aws sts get-caller-identity --query Account --output text):$API_ID/*/*/increment"
fi

# Create API URL
API_URL="https://$API_ID.execute-api.$REGION.amazonaws.com/$API_STAGE/increment"

# Create a code snippet file
echo "๐Ÿ“ Creating HTML code snippet file..."
cat > /Users/myleshenderson/src/f5g/counter-snippet.html <<EOF
<!-- Visitor Counter -->
<div class="visitor-counter">
  <p>Visitor count: <span id="visitor-count">Loading...</span></p>
  <script>
    // Increment counter on page load
    fetch('$API_URL')
      .then(response => response.json())
      .then(data => {
        document.getElementById('visitor-count').textContent = data.count;
      })
      .catch(error => console.error('Error updating counter:', error));
  </script>
</div>
EOF

echo "โœ… Counter setup complete!"
echo "๐Ÿ“Š API URL: $API_URL"
echo "๐Ÿ“ HTML snippet created at: /Users/myleshenderson/src/f5g/counter-snippet.html"
echo "๐Ÿ“‹ Add the HTML snippet to your homepage to display the counter"

setup-iam.sh

This script sets up the IAM user and permissions for deployment.

#!/bin/bash

# Exit on error
set -e

echo "๐Ÿ‘ค Setting up IAM user and permissions..."

# Check if user exists
if aws iam get-user --user-name f5g-pro-deployer >/dev/null 2>&1; then
    echo "๐Ÿ‘ค User f5g-pro-deployer already exists"
else
    echo "๐Ÿ‘ค Creating IAM user..."
    aws iam create-user --user-name f5g-pro-deployer
fi

# Create the policy document
echo "๐Ÿ“ Creating policy document..."
cat > policy.json << EOF
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::f5g.pro",
                "arn:aws:s3:::f5g.pro/*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "cloudfront:CreateInvalidation"
            ],
            "Resource": "*"
        }
    ]
}
EOF

# Check if policy exists
POLICY_ARN="arn:aws:iam::$(aws sts get-caller-identity --query Account --output text):policy/f5g-pro-deploy-policy"
if aws iam get-policy --policy-arn "$POLICY_ARN" >/dev/null 2>&1; then
    echo "๐Ÿ”‘ Policy f5g-pro-deploy-policy already exists"
else
    echo "๐Ÿ”‘ Creating IAM policy..."
    aws iam create-policy --policy-name f5g-pro-deploy-policy --policy-document file://policy.json
fi

# Attach the policy to the user if not already attached
echo "๐Ÿ”— Checking policy attachment..."
if aws iam list-attached-user-policies --user-name f5g-pro-deployer | grep -q "$POLICY_ARN"; then
    echo "๐Ÿ”— Policy already attached to user"
else
    echo "๐Ÿ”— Attaching policy to user..."
    aws iam attach-user-policy --user-name f5g-pro-deployer --policy-arn "$POLICY_ARN"
fi

# List existing access keys
echo "๐Ÿ”‘ Listing existing access keys..."
aws iam list-access-keys --user-name f5g-pro-deployer

echo "โ„น๏ธ  If you need a new access key, please delete one of the existing keys first:"
echo "    aws iam delete-access-key --user-name f5g-pro-deployer --access-key-id ACCESS_KEY_ID"
echo "    Then run this script again to create a new key."

# Clean up
rm policy.json

echo "โœ… IAM setup complete!"
echo "๐Ÿ“ Please save the Access Key ID and Secret Access Key for GitHub secrets!" 

setup-route53.sh

This script configures Route 53 DNS records for the domain.

#!/bin/bash

# Exit on error
set -e

# Load environment variables
source .env

# Check if domain name is set
if [ -z "$DOMAIN_NAME" ]; then
    echo "Error: DOMAIN_NAME is not set in .env file"
    exit 1
fi

echo "Setting up Route 53 configuration for domain: $DOMAIN_NAME"

# Check if hosted zone already exists
echo "Checking for existing hosted zone..."
EXISTING_ZONE=$(aws route53 list-hosted-zones-by-name --dns-name $DOMAIN_NAME --query "HostedZones[?Name=='$DOMAIN_NAME.']" --output text)

if [ -z "$EXISTING_ZONE" ]; then
    echo "Creating new hosted zone for $DOMAIN_NAME..."
    aws route53 create-hosted-zone \
        --name $DOMAIN_NAME \
        --caller-reference $(date +%s) \
        --hosted-zone-config Comment="Hosted zone for $DOMAIN_NAME" \
        | cat
else
    echo "Hosted zone already exists for $DOMAIN_NAME"
fi

# Get the hosted zone ID
HOSTED_ZONE_ID=$(aws route53 list-hosted-zones-by-name --dns-name $DOMAIN_NAME --query "HostedZones[0].Id" --output text | cut -d'/' -f3)

if [ -z "$HOSTED_ZONE_ID" ]; then
    echo "Error: Could not retrieve hosted zone ID"
    exit 1
fi

# Create DNS records
echo "Creating/updating DNS records..."

# Function to create/update DNS record
update_dns_record() {
    local record_name=$1
    local hosted_zone_id=$2
    local cloudfront_domain=$3

    echo "Updating record for $record_name..."
    aws route53 change-resource-record-sets \
        --hosted-zone-id $hosted_zone_id \
        --change-batch '{
            "Changes": [
                {
                    "Action": "UPSERT",
                    "ResourceRecordSet": {
                        "Name": "'"$record_name___2___,
                        "Type": "A",
                        "AliasTarget": {
                            "HostedZoneId": "Z2FDTNDATAQYW2",
                            "DNSName": "'"$cloudfront_domain___2___,
                            "EvaluateTargetHealth": false
                        }
                    }
                }
            ]
        }' | cat
}

# Update root domain record
update_dns_record "$DOMAIN_NAME" "$HOSTED_ZONE_ID" "$CLOUDFRONT_DOMAIN"

# Update www subdomain record
update_dns_record "www.$DOMAIN_NAME" "$HOSTED_ZONE_ID" "$CLOUDFRONT_DOMAIN"

echo "Route 53 configuration completed successfully!" 

setup-s3.sh

This script creates and configures the S3 bucket for website hosting.

#!/bin/bash

# Exit on error
set -e

echo "๐Ÿš€ Setting up S3 bucket for f5g.pro..."

# Check if bucket exists
if aws s3api head-bucket --bucket f5g.pro 2>/dev/null; then
    echo "๐Ÿ“ฆ Bucket f5g.pro already exists"
else
    echo "๐Ÿ“ฆ Creating S3 bucket..."
    aws s3api create-bucket --bucket f5g.pro --region us-east-1
fi

# Disable public access block settings
echo "๐Ÿ”“ Disabling public access block settings..."
aws s3api put-public-access-block \
    --bucket f5g.pro \
    --public-access-block-configuration "BlockPublicAcls=false,IgnorePublicAcls=false,BlockPublicPolicy=false,RestrictPublicBuckets=false"

# Enable static website hosting
echo "๐ŸŒ Enabling static website hosting..."
aws s3 website s3://f5g.pro/ --index-document index.html

# Set the bucket policy
echo "๐Ÿ”’ Setting bucket policy..."
aws s3api put-bucket-policy --bucket f5g.pro --policy '{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::f5g.pro/*"
        }
    ]
}'

echo "โœ… S3 setup complete!" 

setup-ssl.sh

This script requests and validates an SSL certificate for the domain.

#!/bin/bash

# Exit on error
set -e

# Load environment variables
source .env

# Check if domain name is set
if [ -z "$DOMAIN_NAME" ]; then
    echo "Error: DOMAIN_NAME is not set in .env file"
    exit 1
fi

echo "๐Ÿ”’ Setting up SSL certificate for $DOMAIN_NAME..."

# Request a new certificate in us-east-1 (required for CloudFront)
echo "๐Ÿ“ Requesting SSL certificate..."
CERTIFICATE_ARN=$(aws acm request-certificate \
    --domain-name $DOMAIN_NAME \
    --subject-alternative-names "www.$DOMAIN_NAME" \
    --validation-method DNS \
    --region us-east-1 \
    --query 'CertificateArn' \
    --output text)

echo "โœ… Certificate requested with ARN: $CERTIFICATE_ARN"

# Get the DNS validation records
echo "๐Ÿ“ Getting DNS validation records..."
VALIDATION_RECORDS=$(aws acm describe-certificate \
    --certificate-arn $CERTIFICATE_ARN \
    --region us-east-1 \
    --query 'Certificate.DomainValidationOptions[*].[DomainName,ResourceRecord.Name,ResourceRecord.Value]' \
    --output text)

# Get the hosted zone ID
HOSTED_ZONE_ID=$(aws route53 list-hosted-zones-by-name --dns-name $DOMAIN_NAME --query "HostedZones[0].Id" --output text | cut -d'/' -f3)

# Create DNS validation records
echo "๐Ÿ“ Creating DNS validation records..."
while read -r domain name value; do
    echo "Creating record for $domain..."
    aws route53 change-resource-record-sets \
        --hosted-zone-id $HOSTED_ZONE_ID \
        --change-batch '{
            "Changes": [
                {
                    "Action": "UPSERT",
                    "ResourceRecordSet": {
                        "Name": "'"$name___2___,
                        "Type": "CNAME",
                        "TTL": 300,
                        "ResourceRecords": [
                            {
                                "Value": "'"$value___2___
                            }
                        ]
                    }
                }
            ]
        }' | cat
done <<< "$VALIDATION_RECORDS"

echo "โณ Waiting for certificate validation..."
aws acm wait certificate-validated --certificate-arn $CERTIFICATE_ARN --region us-east-1

echo "โœ… SSL certificate is validated and ready to use!"
echo "๐Ÿ“ Certificate ARN: $CERTIFICATE_ARN"
echo "๐Ÿ“ Please update your CloudFront distribution to use this certificate" 

update-cloudfront-cache.sh

This script updates the CloudFront distribution with optimal cache settings.

#!/bin/bash

# Exit on error
set -e

echo "โ˜๏ธ Updating CloudFront distribution cache settings..."

# Get the distribution ID
DISTRIBUTION_ID=$(aws cloudfront list-distributions --query "DistributionList.Items[?Origins.Items[0].DomainName=='f5g.pro.s3.amazonaws.com'].Id" --output text)

if [ -z "$DISTRIBUTION_ID" ]; then
    echo "โŒ Error: CloudFront distribution for f5g.pro not found!"
    exit 1
fi

echo "๐Ÿ” Found CloudFront distribution with ID: $DISTRIBUTION_ID"

# Get the current distribution configuration
echo "๐Ÿ“ฅ Retrieving current configuration..."
aws cloudfront get-distribution-config --id $DISTRIBUTION_ID --output json > distribution-config-old.json

# Extract the ETag value (needed for update)
ETAG=$(grep -o '"ETag"[[:space:]]*:[[:space:]]*"[^"]*"' distribution-config-old.json | sed 's/"ETag"[[:space:]]*:[[:space:]]*"\([^"]*\)"/\1/')

# Extract just the DistributionConfig portion
jq '.DistributionConfig' distribution-config-old.json > distribution-config-extracted.json

# Update the cache policy ID from CachingDisabled to CachingOptimized
# CachingOptimized policy ID: 658327ea-f89d-4fab-a63d-7e88639e58f6
sed -i '' 's/"4135ea2d-6df8-44a3-9df3-4b5a84be39ad"/"658327ea-f89d-4fab-a63d-7e88639e58f6"/g' distribution-config-extracted.json

# Prepare the final configuration file
mv distribution-config-extracted.json distribution-config-new.json

echo "๐Ÿ”„ Updating distribution with optimized caching policy..."
aws cloudfront update-distribution --id $DISTRIBUTION_ID --if-match $ETAG --distribution-config file://distribution-config-new.json > /dev/null

echo "๐Ÿงน Cleaning up temporary files..."
rm distribution-config-old.json distribution-config-new.json

echo "โœ… CloudFront distribution updated with optimized caching policy!"
echo "โฑ๏ธ It may take up to 15-30 minutes for the changes to propagate across all edge locations."
echo "๐ŸŒ After the propagation is complete, your content will be properly cached by CloudFront."

update-cloudfront-ssl.sh

This script updates the CloudFront distribution to use the SSL certificate.

#!/bin/bash

# Exit on error
set -e

# Load environment variables
source .env

# Check if domain name is set
if [ -z "$DOMAIN_NAME" ]; then
    echo "Error: DOMAIN_NAME is not set in .env file"
    exit 1
fi

echo "๐Ÿ”’ Updating CloudFront distribution with SSL certificate..."

# Get the distribution ID
DISTRIBUTION_ID=$(aws cloudfront list-distributions --query "DistributionList.Items[?Origins.Items[0].DomainName=='$DOMAIN_NAME.s3.amazonaws.com'].Id" --output text)

if [ -z "$DISTRIBUTION_ID" ]; then
    echo "Error: Could not find CloudFront distribution for $DOMAIN_NAME"
    exit 1
fi

# Get the current distribution config
echo "๐Ÿ“ Getting current distribution configuration..."
aws cloudfront get-distribution-config --id $DISTRIBUTION_ID --query 'DistributionConfig' > config.json

# Update the config to use the custom SSL certificate
echo "๐Ÿ“ Updating distribution configuration..."
jq '.ViewerCertificate = {
    "ACMCertificateArn": "arn:aws:acm:us-east-1:188150609925:certificate/e0ea7099-c492-4791-975d-f421f45c131e",
    "SSLSupportMethod": "sni-only",
    "MinimumProtocolVersion": "TLSv1.2_2021"
} | .Aliases.Items = ["'"$DOMAIN_NAME___1___, "www.'"$DOMAIN_NAME___3___] | .Aliases.Quantity = 2' config.json > updated-config.json

# Update the distribution
echo "๐Ÿš€ Updating CloudFront distribution..."
aws cloudfront update-distribution \
    --id $DISTRIBUTION_ID \
    --distribution-config file://updated-config.json \
    --if-match $(aws cloudfront get-distribution --id $DISTRIBUTION_ID --query 'ETag' --output text) | cat

# Clean up
rm config.json updated-config.json

echo "โœ… CloudFront distribution update initiated!"
echo "โณ This may take 15-30 minutes to complete..."
echo "๐Ÿ“ You can check the status with: aws cloudfront get-distribution --id $DISTRIBUTION_ID" 

update-counter-url.sh

This script updates the visitor counter API URL after deployment.

#!/bin/bash

# Exit on error
set -e

echo "๐Ÿ”„ Updating Counter API URL in build script..."

# Check if API URL argument is provided
if [ -z "$1" ]; then
    echo "โŒ Error: Please provide the Counter API URL as an argument"
    echo "Usage: ./scripts/update-counter-url.sh <API_URL>"
    exit 1
fi

COUNTER_API_URL="$1"
BUILD_JS_FILE="/Users/myleshenderson/src/f5g/build.js"

# Update the Counter API URL in the build.js file
echo "๐Ÿ“ Setting Counter API URL to: $COUNTER_API_URL"

# Use a temporary file for the replacement
cat "$BUILD_JS_FILE" | awk -v url="$COUNTER_API_URL" '{gsub(/const counterApiUrl = process.env.COUNTER_API_URL \|\| ".*";/, "const counterApiUrl = process.env.COUNTER_API_URL || \"" url "\";"); print}' > /tmp/build.js.tmp
mv /tmp/build.js.tmp "$BUILD_JS_FILE"

echo "โœ… Counter API URL updated successfully!"
echo "๐Ÿ”จ Run 'node build.js' to rebuild the site with the new Counter API URL"
Visitors
F5G.pro web counter