Lab 2: Sitio Secundario (Fallback)
Lab 2: Sitio Secundario – Página de Mantenimiento
El sitio secundario es la página de contingencia que verán los usuarios cuando el sitio primario no esté disponible. Debe ser estática, altamente disponible y serverless.
Usuario → AWS Amplify Hosting → "Página de Mantenimiento" (default)
→ CloudFront + S3 (alt.) → "Página de Mantenimiento"Cargar variables de entorno
source ~/global.envOpción A: CloudFormation (Base) — AWS Amplify (Recomendado)
AWS Amplify Hosting es la opción más simple: sin buckets S3, sin distribuciones CloudFront, sin esperas de propagación. El sitio queda disponible en menos de 2 minutos con HTTPS automático.
1. Crear el template CloudFormation
cat > /tmp/secondary-site.yaml << 'TEMPLATE_EOF'
AWSTemplateFormatVersion: '2010-09-09'
Description: 'roLearning - Route53 ARC Workshop - Sitio Secundario (AWS Amplify)'
Resources:
FallbackAmplifyApp:
Type: AWS::Amplify::App
Properties:
Name: route53-arc-fallback
Description: "Sitio de mantenimiento - roLearning Workshop"
Platform: WEB
BuildSpec: |
version: 1
frontend:
phases:
build:
commands: []
artifacts:
baseDirectory: /
files:
- '**/*'
Tags:
- { Key: Workshop, Value: route53-arc }
FallbackAmplifyBranch:
Type: AWS::Amplify::Branch
Properties:
AppId: !GetAtt FallbackAmplifyApp.AppId
BranchName: main
Stage: PRODUCTION
EnableAutoBuild: false
Tags:
- { Key: Workshop, Value: route53-arc }
Outputs:
AmplifyAppId:
Value: !GetAtt FallbackAmplifyApp.AppId
Export: { Name: route53-arc-amplify-app-id }
AmplifyDefaultDomain:
Value: !GetAtt FallbackAmplifyApp.DefaultDomain
Export: { Name: route53-arc-amplify-domain }
TEMPLATE_EOF2. Desplegar Stack y subir el contenido
aws cloudformation deploy \
--template-file /tmp/secondary-site.yaml \
--stack-name route53-arc-secondary \
--capabilities CAPABILITY_IAM \
--region $AWS_REGION
export AMPLIFY_APP_ID=$(aws cloudformation describe-stacks \
--stack-name route53-arc-secondary --region $AWS_REGION \
--query 'Stacks[0].Outputs[?OutputKey==`AmplifyAppId`].OutputValue' --output text)
export AMPLIFY_DOMAIN=$(aws cloudformation describe-stacks \
--stack-name route53-arc-secondary --region $AWS_REGION \
--query 'Stacks[0].Outputs[?OutputKey==`AmplifyDefaultDomain`].OutputValue' --output text)
# Crear la página de mantenimiento HTML
cat > /tmp/fallback-index.html << 'HTML'
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Mantenimiento – roLearning</title>
<style>
* { margin:0; padding:0; box-sizing:border-box; }
body { font-family:'Segoe UI',Arial,sans-serif; background:#0f172a; color:#e2e8f0; display:flex; align-items:center; justify-content:center; min-height:100vh; }
.container { text-align:center; padding:40px 60px; background:#1e293b; border-radius:16px; box-shadow:0 8px 32px rgba(0,0,0,.5); max-width:600px; width:90%; }
h1 { font-size:2em; color:#f59e0b; margin-bottom:12px; }
p { color:#94a3b8; line-height:1.6; margin-bottom:8px; }
.badge { display:inline-block; background:#f59e0b; color:#0f172a; padding:6px 20px; border-radius:20px; font-weight:bold; font-size:.85em; margin:16px 0; }
</style>
</head>
<body>
<div class="container">
<h1>⚠️ Sitio en Mantenimiento</h1>
<div class="badge">MANTENIMIENTO PROGRAMADO</div>
<p>Estamos realizando tareas de mantenimiento para mejorar nuestros servicios.</p>
<p><strong>Por favor, inténtelo de nuevo en unos minutos.</strong></p>
<p style="margin-top:20px; font-size:0.8em; color:#475569;">roLearning – AWS Route 53 ARC Workshop (CloudFormation + Amplify)</p>
</div>
</body>
</html>
HTML
# Crear el HTML directamente como index.html y empaquetar en un único ZIP
cat > /tmp/index.html << 'HTML'
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Mantenimiento – roLearning</title>
<style>
* { margin:0; padding:0; box-sizing:border-box; }
body { font-family:'Segoe UI',Arial,sans-serif; background:#0f172a; color:#e2e8f0; display:flex; align-items:center; justify-content:center; min-height:100vh; }
.container { text-align:center; padding:40px 60px; background:#1e293b; border-radius:16px; box-shadow:0 8px 32px rgba(0,0,0,.5); max-width:600px; width:90%; }
h1 { font-size:2em; color:#f59e0b; margin-bottom:12px; }
p { color:#94a3b8; line-height:1.6; margin-bottom:8px; }
.badge { display:inline-block; background:#f59e0b; color:#0f172a; padding:6px 20px; border-radius:20px; font-weight:bold; font-size:.85em; margin:16px 0; }
</style>
</head>
<body>
<div class="container">
<h1>⚠️ Sitio en Mantenimiento</h1>
<div class="badge">MANTENIMIENTO PROGRAMADO</div>
<p>Estamos realizando tareas de mantenimiento para mejorar nuestros servicios.</p>
<p><strong>Por favor, inténtelo de nuevo en unos minutos.</strong></p>
<p style="margin-top:20px; font-size:0.8em; color:#475569;">roLearning – AWS Route 53 ARC Workshop (CloudFormation + Amplify)</p>
</div>
</body>
</html>
HTML
cd /tmp && zip -q fallback-site.zip index.html
# Iniciar un deployment manual en Amplify
DEPLOY_RESULT=$(aws amplify create-deployment \
--app-id $AMPLIFY_APP_ID \
--branch-name main \
--region $AWS_REGION \
--output json)
UPLOAD_URL=$(echo $DEPLOY_RESULT | python3 -c "import json,sys; d=json.load(sys.stdin); print(d['zipUploadUrl'])")
JOB_ID=$(echo $DEPLOY_RESULT | python3 -c "import json,sys; d=json.load(sys.stdin); print(d['jobId'])")
echo "📤 Subiendo contenido al deployment Amplify..."
curl -s -X PUT -H "Content-Type: application/zip" --data-binary @/tmp/fallback-site.zip "$UPLOAD_URL"
# Iniciar el deployment
aws amplify start-deployment \
--app-id $AMPLIFY_APP_ID \
--branch-name main \
--job-id $JOB_ID \
--region $AWS_REGION
echo "⏳ Esperando que el deployment de Amplify finalice..."
for i in {1..12}; do
STATUS=$(aws amplify get-job \
--app-id $AMPLIFY_APP_ID \
--branch-name main \
--job-id $JOB_ID \
--region $AWS_REGION \
--query 'job.summary.status' --output text 2>/dev/null)
echo " [$i/12] Estado del deployment: $STATUS"
[ "$STATUS" = "SUCCEED" ] && break
[ "$STATUS" = "FAILED" ] && echo "❌ Deployment falló" && break
sleep 10
done
export FALLBACK_DOMAIN="https://main.${AMPLIFY_DOMAIN}"
echo "🌐 Sitio Fallback (Amplify): $FALLBACK_DOMAIN"
# Persistir en global.env para que esté disponible en labs siguientes
if grep -q "FALLBACK_DOMAIN" ~/global.env 2>/dev/null; then
sed -i '' "s|.*FALLBACK_DOMAIN.*|export FALLBACK_DOMAIN=\"${FALLBACK_DOMAIN}\"|" ~/global.env 2>/dev/null || \
sed -i "s|.*FALLBACK_DOMAIN.*|export FALLBACK_DOMAIN=\"${FALLBACK_DOMAIN}\"|" ~/global.env
else
echo "export FALLBACK_DOMAIN=\"${FALLBACK_DOMAIN}\"" >> ~/global.env
fi
# Persistir AMPLIFY_APP_ID para re-deploys manuales si fuera necesario
if grep -q "AMPLIFY_APP_ID" ~/global.env 2>/dev/null; then
sed -i '' "s|.*AMPLIFY_APP_ID.*|export AMPLIFY_APP_ID=\"${AMPLIFY_APP_ID}\"|" ~/global.env 2>/dev/null || \
sed -i "s|.*AMPLIFY_APP_ID.*|export AMPLIFY_APP_ID=\"${AMPLIFY_APP_ID}\"|" ~/global.env
else
echo "export AMPLIFY_APP_ID=\"${AMPLIFY_APP_ID}\"" >> ~/global.env
fi
echo "✅ FALLBACK_DOMAIN y AMPLIFY_APP_ID guardados en ~/global.env"Opción A Alternativa: CloudFormation — S3 + CloudFront
Aviso
⏱️ Tiempo de espera: La distribución CloudFront tarda entre 15 y 20 minutos en propagarse globalmente. Durante ese tiempo, la verificación devolverá 403 o timeout — esto es normal. No avances al Lab 3 hasta confirmar que el sitio responde con HTTP 200.
Esta opción despliega un bucket S3 privado protegido con Origin Access Control (OAC) y una distribución global de CloudFront.
1. Crear el template CloudFormation
cat > /tmp/secondary-site-cf.yaml << 'TEMPLATE_EOF'
AWSTemplateFormatVersion: '2010-09-09'
Description: 'roLearning - Route53 ARC Workshop - Sitio Secundario (S3 + CloudFront)'
Parameters:
BucketName:
Type: String
Description: "Nombre único del bucket S3"
Resources:
FallbackBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref BucketName
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
Tags: [{ Key: Workshop, Value: route53-arc }]
CloudFrontOAC:
Type: AWS::CloudFront::OriginAccessControl
Properties:
OriginAccessControlConfig:
Name: route53-arc-fallback-oac-cfn
OriginAccessControlOriginType: s3
SigningBehavior: always
SigningProtocol: sigv4
FallbackBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref FallbackBucket
PolicyDocument:
Statement:
- Sid: AllowCloudFrontServicePrincipal
Effect: Allow
Principal: { Service: cloudfront.amazonaws.com }
Action: s3:GetObject
Resource: !Sub "${FallbackBucket.Arn}/*"
Condition:
StringEquals:
"AWS:SourceArn": !Sub "arn:aws:cloudfront::${AWS::AccountId}:distribution/${FallbackDistribution}"
FallbackDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Enabled: true
DefaultRootObject: index.html
Comment: "roLearning Route53 ARC Fallback Site"
HttpVersion: http2
Origins:
- Id: S3FallbackOrigin
DomainName: !GetAtt FallbackBucket.RegionalDomainName
OriginAccessControlId: !Ref CloudFrontOAC
S3OriginConfig: { OriginAccessIdentity: "" }
DefaultCacheBehavior:
ViewerProtocolPolicy: redirect-to-https
TargetOriginId: S3FallbackOrigin
CachePolicyId: 658327ea-f89d-4fab-a63d-7e88639e58f6
AllowedMethods: [GET, HEAD]
CachedMethods: [GET, HEAD]
CustomErrorResponses:
- ErrorCode: 403
ResponseCode: 200
ResponsePagePath: /index.html
- ErrorCode: 404
ResponseCode: 200
ResponsePagePath: /index.html
Tags: [{ Key: Workshop, Value: route53-arc }]
Outputs:
FallbackBucketName:
Value: !Ref FallbackBucket
Export: { Name: route53-arc-fallback-bucket }
CloudFrontDomain:
Value: !GetAtt FallbackDistribution.DomainName
Export: { Name: route53-arc-cf-domain }
CloudFrontDistributionId:
Value: !Ref FallbackDistribution
Export: { Name: route53-arc-cf-distribution-id }
TEMPLATE_EOF2. Desplegar Stack y subir HTML
export BUCKET_NAME="route53-arc-fallback-${AWS_ACCOUNT_ID}"
aws cloudformation deploy \
--template-file /tmp/secondary-site-cf.yaml \
--stack-name route53-arc-secondary \
--capabilities CAPABILITY_IAM \
--region $AWS_REGION \
--parameter-overrides BucketName=$BUCKET_NAME
export CF_DOMAIN=$(aws cloudformation describe-stacks \
--stack-name route53-arc-secondary --region $AWS_REGION \
--query 'Stacks[0].Outputs[?OutputKey==`CloudFrontDomain`].OutputValue' --output text)
cat > /tmp/fallback-index.html << 'HTML'
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Mantenimiento – roLearning</title>
<style>
* { margin:0; padding:0; box-sizing:border-box; }
body { font-family:'Segoe UI',Arial,sans-serif; background:#0f172a; color:#e2e8f0; display:flex; align-items:center; justify-content:center; min-height:100vh; }
.container { text-align:center; padding:40px 60px; background:#1e293b; border-radius:16px; box-shadow:0 8px 32px rgba(0,0,0,.5); max-width:600px; width:90%; }
h1 { font-size:2em; color:#f59e0b; margin-bottom:12px; }
p { color:#94a3b8; line-height:1.6; margin-bottom:8px; }
.badge { display:inline-block; background:#f59e0b; color:#0f172a; padding:6px 20px; border-radius:20px; font-weight:bold; font-size:.85em; margin:16px 0; }
</style>
</head>
<body>
<div class="container">
<h1>⚠️ Sitio en Mantenimiento</h1>
<div class="badge">MANTENIMIENTO PROGRAMADO</div>
<p>Estamos realizando tareas de mantenimiento para mejorar nuestros servicios.</p>
<p><strong>Por favor, inténtelo de nuevo en unos minutos.</strong></p>
<p style="margin-top:20px; font-size:0.8em; color:#475569;">roLearning – AWS Route 53 ARC Workshop (CloudFormation + CloudFront)</p>
</div>
</body>
</html>
HTML
aws s3 cp /tmp/fallback-index.html s3://$BUCKET_NAME/index.html --content-type "text/html" --region $AWS_REGION
export FALLBACK_DOMAIN="https://$CF_DOMAIN"
echo "🌐 Sitio Fallback (CloudFront): $FALLBACK_DOMAIN"
echo "⏳ Recordá que CloudFront puede tardar 15-20 min en propagarse. Avanzá al Lab 3 y volvé a verificar."Opción B: Terraform — AWS Amplify (Recomendado)
Detalles
🚫 Opción B requiere terminal local — no uses CloudShell con Terraform. Ver Lab 0 para más detalles.
1. Configurar el módulo Terraform
cd ~/route53-arc-tf/02_secondary
# variables.tf
cat > variables.tf << 'EOF'
variable "aws_region" { type = string; default = "us-east-1" }
variable "project_tag" { type = string; default = "route53-arc" }
EOF
# main.tf
cat > main.tf << 'EOF'
terraform {
required_version = ">= 1.5"
required_providers {
aws = { source = "hashicorp/aws", version = "~> 5.0" }
}
}
provider "aws" {
region = var.aws_region
default_tags { tags = { Workshop = var.project_tag, ManagedBy = "Terraform" } }
}
resource "aws_amplify_app" "fallback" {
name = "route53-arc-fallback"
description = "Sitio de mantenimiento - roLearning Workshop"
platform = "WEB"
build_spec = <<-YAML
version: 1
frontend:
phases:
build:
commands: []
artifacts:
baseDirectory: /
files: ['**/*']
YAML
}
resource "aws_amplify_branch" "main" {
app_id = aws_amplify_app.fallback.id
branch_name = "main"
stage = "PRODUCTION"
enable_auto_build = false
}
EOF
# outputs.tf
cat > outputs.tf << 'EOF'
output "amplify_app_id" {
value = aws_amplify_app.fallback.id
}
output "fallback_domain" {
value = "https://main.${aws_amplify_app.fallback.default_domain}"
}
EOF2. Aplicar Terraform y desplegar el contenido
terraform init
terraform apply -auto-approve
export AMPLIFY_APP_ID=$(terraform output -raw amplify_app_id)
export FALLBACK_DOMAIN=$(terraform output -raw fallback_domain)
# Crear la página de mantenimiento HTML
cat > /tmp/index.html << 'HTML'
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Mantenimiento - roLearning Workshop</title>
<style>
* { margin:0; padding:0; box-sizing:border-box; }
body { font-family:'Segoe UI',Arial,sans-serif; background:#0f172a; color:#e2e8f0; display:flex; align-items:center; justify-content:center; min-height:100vh; }
.container { text-align:center; padding:40px 60px; background:#1e293b; border-radius:16px; box-shadow:0 8px 32px rgba(0,0,0,.5); max-width:600px; width:90%; }
h1 { font-size:2em; color:#f59e0b; margin-bottom:12px; }
p { color:#94a3b8; line-height:1.6; margin-bottom:8px; }
.badge { display:inline-block; background:#f59e0b; color:#0f172a; padding:6px 20px; border-radius:20px; font-weight:bold; font-size:.85em; margin:16px 0; }
</style>
</head>
<body>
<div class="container">
<h1>⚠️ Sitio en Mantenimiento</h1>
<div class="badge">MANTENIMIENTO PROGRAMADO</div>
<p>Estamos realizando tareas de mantenimiento para mejorar nuestros servicios.</p>
<p><strong>Por favor, inténtelo de nuevo en unos minutos.</strong></p>
<p style="margin-top:20px; font-size:0.8em; color:#475569;">roLearning – AWS Route 53 ARC Workshop (Terraform + Amplify)</p>
</div>
</body>
</html>
HTML
# Empaquetar y subir el contenido al branch de Amplify
cd /tmp && zip -q fallback-site.zip index.html
echo "📤 Creando deployment en Amplify..."
DEPLOY_RESULT=$(aws amplify create-deployment \
--app-id $AMPLIFY_APP_ID \
--branch-name main \
--region $AWS_REGION \
--output json)
UPLOAD_URL=$(echo $DEPLOY_RESULT | python3 -c "import json,sys; d=json.load(sys.stdin); print(d['zipUploadUrl'])")
JOB_ID=$(echo $DEPLOY_RESULT | python3 -c "import json,sys; d=json.load(sys.stdin); print(d['jobId'])")
curl -s -X PUT -H "Content-Type: application/zip" --data-binary @/tmp/fallback-site.zip "$UPLOAD_URL"
echo "✅ ZIP subido"
aws amplify start-deployment \
--app-id $AMPLIFY_APP_ID \
--branch-name main \
--job-id $JOB_ID \
--region $AWS_REGION
echo "⏳ Esperando que el deployment finalice..."
for i in {1..12}; do
STATUS=$(aws amplify get-job \
--app-id $AMPLIFY_APP_ID \
--branch-name main \
--job-id $JOB_ID \
--region $AWS_REGION \
--query 'job.summary.status' --output text 2>/dev/null)
echo " [$i/12] Estado: $STATUS"
[ "$STATUS" = "SUCCEED" ] && break
[ "$STATUS" = "FAILED" ] && echo "❌ Deployment falló" && break
sleep 10
done
echo "🌐 Sitio Fallback (Amplify): $FALLBACK_DOMAIN"
# Persistir en global.env para que esté disponible en labs siguientes
if grep -q "FALLBACK_DOMAIN" ~/global.env 2>/dev/null; then
sed -i '' "s|.*FALLBACK_DOMAIN.*|export FALLBACK_DOMAIN=\"${FALLBACK_DOMAIN}\"|" ~/global.env 2>/dev/null || \
sed -i "s|.*FALLBACK_DOMAIN.*|export FALLBACK_DOMAIN=\"${FALLBACK_DOMAIN}\"|" ~/global.env
else
echo "export FALLBACK_DOMAIN=\"${FALLBACK_DOMAIN}\"" >> ~/global.env
fi
if grep -q "AMPLIFY_APP_ID" ~/global.env 2>/dev/null; then
sed -i '' "s|.*AMPLIFY_APP_ID.*|export AMPLIFY_APP_ID=\"${AMPLIFY_APP_ID}\"|" ~/global.env 2>/dev/null || \
sed -i "s|.*AMPLIFY_APP_ID.*|export AMPLIFY_APP_ID=\"${AMPLIFY_APP_ID}\"|" ~/global.env
else
echo "export AMPLIFY_APP_ID=\"${AMPLIFY_APP_ID}\"" >> ~/global.env
fi
echo "✅ FALLBACK_DOMAIN y AMPLIFY_APP_ID guardados en ~/global.env"Opción B Alternativa: Terraform — S3 + CloudFront
Aviso
⏱️ Tiempo de espera: La distribución CloudFront tarda entre 15 y 20 minutos en propagarse. La verificación devolverá 403 durante ese tiempo — es normal. No avances al Lab 3 hasta confirmar HTTP 200.
cd ~/route53-arc-tf/02_secondary
cat > main.tf << 'EOF'
terraform {
required_version = ">= 1.5"
required_providers {
aws = { source = "hashicorp/aws", version = "~> 5.0" }
}
}
provider "aws" {
region = var.aws_region
default_tags { tags = { Workshop = var.project_tag, ManagedBy = "Terraform" } }
}
data "aws_caller_identity" "current" {}
resource "aws_s3_bucket" "fallback" {
bucket = "route53-arc-fallback-${data.aws_caller_identity.current.account_id}"
force_destroy = true
}
resource "aws_s3_bucket_public_access_block" "fallback" {
bucket = aws_s3_bucket.fallback.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
resource "aws_cloudfront_origin_access_control" "fallback" {
name = "route53-arc-fallback-oac-tf"
origin_access_control_origin_type = "s3"
signing_behavior = "always"
signing_protocol = "sigv4"
}
resource "aws_cloudfront_distribution" "fallback" {
enabled = true
default_root_object = "index.html"
comment = "roLearning Route53 ARC Fallback Site"
http_version = "http2"
origin {
domain_name = aws_s3_bucket.fallback.bucket_regional_domain_name
origin_id = "S3FallbackOrigin"
origin_access_control_id = aws_cloudfront_origin_access_control.fallback.id
}
default_cache_behavior {
target_origin_id = "S3FallbackOrigin"
viewer_protocol_policy = "redirect-to-https"
allowed_methods = ["GET", "HEAD"]
cached_methods = ["GET", "HEAD"]
cache_policy_id = "658327ea-f89d-4fab-a63d-7e88639e58f6"
}
custom_error_response {
error_code = 403
response_code = 200
response_page_path = "/index.html"
}
restrictions {
geo_restriction { restriction_type = "none" }
}
viewer_certificate { cloudfront_default_certificate = true }
}
resource "aws_s3_bucket_policy" "fallback" {
bucket = aws_s3_bucket.fallback.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Sid = "AllowCloudFrontServicePrincipal"
Effect = "Allow"
Principal = { Service = "cloudfront.amazonaws.com" }
Action = "s3:GetObject"
Resource = "${aws_s3_bucket.fallback.arn}/*"
Condition = { StringEquals = { "AWS:SourceArn" = aws_cloudfront_distribution.fallback.arn } }
}]
})
}
EOF
cat > outputs.tf << 'EOF'
output "fallback_domain" { value = "https://${aws_cloudfront_distribution.fallback.domain_name}" }
output "fallback_bucket" { value = aws_s3_bucket.fallback.id }
output "cf_distribution_id"{ value = aws_cloudfront_distribution.fallback.id }
EOF
terraform init && terraform apply -auto-approve
export FALLBACK_DOMAIN=$(terraform output -raw fallback_domain)
BUCKET_NAME=$(terraform output -raw fallback_bucket)
# Subir el HTML al bucket
cat > /tmp/fallback-index.html << 'HTML'
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Mantenimiento – roLearning</title>
<style>
* { margin:0; padding:0; box-sizing:border-box; }
body { font-family:'Segoe UI',Arial,sans-serif; background:#0f172a; color:#e2e8f0; display:flex; align-items:center; justify-content:center; min-height:100vh; }
.container { text-align:center; padding:40px 60px; background:#1e293b; border-radius:16px; box-shadow:0 8px 32px rgba(0,0,0,.5); max-width:600px; width:90%; }
h1 { font-size:2em; color:#f59e0b; margin-bottom:12px; }
p { color:#94a3b8; line-height:1.6; margin-bottom:8px; }
.badge { display:inline-block; background:#f59e0b; color:#0f172a; padding:6px 20px; border-radius:20px; font-weight:bold; font-size:.85em; margin:16px 0; }
</style>
</head>
<body>
<div class="container">
<h1>⚠️ Sitio en Mantenimiento</h1>
<div class="badge">MANTENIMIENTO PROGRAMADO</div>
<p>Estamos realizando tareas de mantenimiento para mejorar nuestros servicios.</p>
<p><strong>Por favor, inténtelo de nuevo en unos minutos.</strong></p>
<p style="margin-top:20px; font-size:0.8em; color:#475569;">roLearning – AWS Route 53 ARC Workshop (Terraform + CloudFront)</p>
</div>
</body>
</html>
HTML
aws s3 cp /tmp/fallback-index.html s3://$BUCKET_NAME/index.html --content-type "text/html" --region $AWS_REGION
echo "🌐 Sitio Fallback (CloudFront): $FALLBACK_DOMAIN"
echo "⏳ CloudFront puede tardar 15-20 min en propagarse."✅ Verificación del Lab 2
echo "=== Verificación Lab 2: Sitio Secundario ==="
echo "Probando endpoint fallback: $FALLBACK_DOMAIN"
STATUS=$(curl -s -o /dev/null -w "%{http_code}" $FALLBACK_DOMAIN)
[ "$STATUS" = "200" ] \
&& echo "✅ Sitio fallback HTTPS responde: HTTP $STATUS" \
|| echo "⚠️ Estado HTTP: $STATUS — si usaste CloudFront, esperá 15-20 min y re-ejecutá esta verificación"Siguiente paso → Lab 3: Route 53 ARC