Back

5_storage_deploy

#!/usr/bin/env bash
# ================================================================
#  STATIC WEBSITE — DEPLOY
#  Deploy a Static Website on AWS S3
#  RUN: chmod +x 5_storage_deploy.sh && ./5_storage_deploy.sh
#  STATE: $HOME/aws_state_storage.txt
# ================================================================
set -euo pipefail

REGION="ap-south-1"
STATE_FILE="$HOME/aws_state_storage.txt"

# ── Step 0: Load existing state ─────────────────────────────
if [[ -f "$STATE_FILE" ]]; then
  source "$STATE_FILE"
  info "  Loaded existing bucket: $BUCKET"
else
  BUCKET="practical-static-site-$(date +%s)"
fi
SITE_DIR="$HOME/web_content"

G='\033[0;32m'; B='\033[0;34m'; Y='\033[1;33m'; NC='\033[0m'
info()    { echo -e "${B}[INFO]${NC}  $*"; }
success() { echo -e "${G}[OK]${NC}    $*"; }
banner()  { echo -e "\n${Y}══════════════════════════════════════════${NC}"; \
            echo -e "${Y}  $*${NC}"; \
            echo -e "${Y}══════════════════════════════════════════${NC}\n"; }

banner "STATIC WEBSITE — S3 Hosting"

# ── Step 1: Create S3 Bucket ──────────────────────────────────
info "Step 1 — S3 Bucket: $BUCKET"
if aws s3api head-bucket --bucket "$BUCKET" --region "$REGION" 2>/dev/null; then
  info "  Bucket '$BUCKET' already exists. Using it."
else
  info "  Creating bucket: $BUCKET"
  aws s3api create-bucket \
    --bucket "$BUCKET" \
    --region "$REGION" \
    --create-bucket-configuration LocationConstraint="$REGION" > /dev/null
  success "Bucket created: $BUCKET"
fi

info "  Disabling Block Public Access..."
aws s3api put-public-access-block \
  --bucket "$BUCKET" \
  --public-access-block-configuration "BlockPublicAcls=false,IgnorePublicAcls=false,BlockPublicPolicy=false,RestrictPublicBuckets=false" \
  --region "$REGION" 2>/dev/null || true
success "Public access unblocked."

# ── Step 2: Bucket Policy ─────────────────────────────────────
info "Step 2 — Applying Public Read Policy"
POLICY='{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PublicRead",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::'$BUCKET'/*"
    }
  ]
}'
aws s3api put-bucket-policy --bucket "$BUCKET" --policy "$POLICY" --region "$REGION"
success "Bucket policy applied."

info "Step 3 — Enabling Static Website Hosting"
aws s3api put-bucket-website --bucket "$BUCKET" \
  --website-configuration '{"IndexDocument":{"Suffix":"index.html"},"ErrorDocument":{"Key":"error.html"}}' \
  --region "$REGION"
success "Static website hosting enabled."

info "Step 5 — Creating website files"
mkdir -p "$SITE_DIR"
cat > "$SITE_DIR/index.html" <<'HTML'
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Secure Login Portal — S3 Static Host</title>
    <style>
        :root { --primary: #6366f1; --bg: #0f172a; --card: #1e293b; --input: #334155; }
        body { font-family: 'Inter', system-ui, sans-serif; background: var(--bg); color: white; margin: 0; display: flex; align-items: center; justify-content: center; min-height: 100vh; }
        .login-card { background: var(--card); padding: 2.5rem; border-radius: 1rem; width: 100%; max-width: 400px; box-shadow: 0 25px 50px -12px rgba(0,0,0,0.5); border: 1px solid rgba(255,255,255,0.1); }
        .logo { font-size: 2rem; margin-bottom: 2rem; text-align: center; }
        h1 { font-size: 1.5rem; font-weight: 700; margin-bottom: 0.5rem; text-align: center; }
        p.subtitle { color: #94a3b8; font-size: 0.875rem; text-align: center; margin-bottom: 2rem; }
        .form-group { margin-bottom: 1.25rem; }
        label { display: block; font-size: 0.875rem; font-weight: 500; margin-bottom: 0.5rem; color: #cbd5e1; }
        input { width: 100%; padding: 0.75rem 1rem; background: var(--input); border: 1px solid rgba(255,255,255,0.1); border-radius: 0.5rem; color: white; box-sizing: border-box; transition: 0.2s; }
        input:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 2px rgba(99,102,241,0.2); }
        button { width: 100%; padding: 0.75rem; background: var(--primary); color: white; border: none; border-radius: 0.5rem; font-weight: 600; cursor: pointer; transition: 0.2s; margin-top: 1rem; }
        button:hover { background: #4f46e5; }
        .footer-links { margin-top: 1.5rem; display: flex; justify-content: space-between; font-size: 0.75rem; color: #64748b; }
        .footer-links a { color: var(--primary); text-decoration: none; }
    </style>
</head>
<body>
    <div class="login-card">
        <div class="logo">👤</div>
        <h1>Portal Login</h1>
        <p class="subtitle">Cloud Infrastructure Management</p>
        <div class="form-group">
            <label>Employee Email</label>
            <input type="email" placeholder="name@company.com">
        </div>
        <div class="form-group">
            <label>Access Key</label>
            <input type="password" placeholder="••••••••">
        </div>
        <button type="submit">Unlock System</button>
        <div class="footer-links">
            <a href="error.html">Forgot Key?</a>
            <span>Powered by Amazon S3</span>
        </div>
    </div>
</body>
</html>
HTML

cat > "$SITE_DIR/error.html" <<'HTML'
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Access Denied — 404</title>
    <style>
        :root { --bg: #0f172a; --card: #1e293b; --danger: #ef4444; }
        body { font-family: 'Inter', system-ui, sans-serif; background: var(--bg); color: white; margin: 0; display: flex; align-items: center; justify-content: center; min-height: 100vh; }
        .error-card { background: var(--card); padding: 3rem; border-radius: 1rem; text-align: center; max-width: 400px; border: 1px solid rgba(239,68,68,0.2); }
        .icon { font-size: 4rem; margin-bottom: 1rem; color: var(--danger); }
        h1 { font-size: 2rem; margin-bottom: 0.5rem; }
        p { color: #94a3b8; margin-bottom: 2rem; line-height: 1.5; }
        .btn { display: inline-block; padding: 0.75rem 1.5rem; background: rgba(255,255,255,0.05); color: white; text-decoration: none; border-radius: 0.5rem; border: 1px solid rgba(255,255,255,0.1); transition: 0.2s; }
        .btn:hover { background: rgba(255,255,255,0.1); }
    </style>
</head>
<body>
    <div class="error-card">
        <div class="icon">⚠️</div>
        <h1>404 Error</h1>
        <p>The requested security protocol or page was not found on this server. Please return to the primary portal.</p>
        <a href="index.html" class="btn">Back to Login</a>
    </div>
</body>
</html>
HTML
success "HTML files created in $SITE_DIR"

info "Step 6 — Uploading files to S3"
aws s3 cp "$SITE_DIR/index.html" "s3://${BUCKET}/index.html" --content-type "text/html"
aws s3 cp "$SITE_DIR/error.html" "s3://${BUCKET}/error.html" --content-type "text/html"
success "Files uploaded."

info "Step 7 — Verifying bucket contents"
aws s3 ls "s3://$BUCKET/" --human-readable

INDEX_URL="https://${BUCKET}.s3.${REGION}.amazonaws.com/index.html"
ERROR_URL="https://${BUCKET}.s3.${REGION}.amazonaws.com/error.html"

cat > "$STATE_FILE" <<EOF
REGION=$REGION
BUCKET=$BUCKET
INDEX_URL=$INDEX_URL
ERROR_URL=$ERROR_URL
SITE_DIR=$SITE_DIR
EOF

banner "STATIC WEBSITE — COMPLETE SUMMARY"
cat <<SUMMARY
  ╔══════════════════════════════════════════════════════════════╗
  ║              RESOURCES CREATED                               ║
  ╠═══════════════════════╦══════════════════════════════════════╣
  ║ Resource              ║ Value                                ║
  ╠═══════════════════════╬══════════════════════════════════════╣
  ║ S3 Bucket             ║ $BUCKET                              ║
  ║ Website URL (HTTP)    ║ http://${BUCKET}.s3-website.${REGION}.amazonaws.com ║
  ║ Error URL (HTTP)      ║ http://${BUCKET}.s3-website.${REGION}.amazonaws.com/error.html ║
  ║ Hosting Type          ║ Static Website (index.html)          ║
  ║ Bucket Policy         ║ Public read (s3:GetObject)           ║
  ║ Files Uploaded        ║ index.html, error.html               ║
  ║ Region                ║ $REGION                              ║
  ╠═══════════════════════╩══════════════════════════════════════╣
  ║              DETAILS NEEDED TO DELETE                        ║
  ╠══════════════════════════════════════════════════════════════╣
  ║  Bucket Name : $BUCKET                                       ║
  ║  Region      : $REGION                                       ║
  ║  State File  : $STATE_FILE                                   ║
  ╠══════════════════════════════════════════════════════════════╣
  ║  Run: ./5_storage_cleanup.sh  (reads state file automatically) ║
  ╚══════════════════════════════════════════════════════════════╝

  Website URL (HTTP): http://${BUCKET}.s3-website.${REGION}.amazonaws.com
  Error URL (HTTP)  : http://${BUCKET}.s3-website.${REGION}.amazonaws.com/error.html
SUMMARY