Полная настройка S3 для CRC
Создание и конфигурация бакета
# Создаём бакет
aws s3 mb s3://ivan-petrov-resume --region us-east-1
# Включаем статический хостинг
aws s3 website s3://ivan-petrov-resume \
--index-document index.html \
--error-document error.html
# Блокируем публичный доступ (CloudFront будет единственным путём)
aws s3api put-public-access-block \
--bucket ivan-petrov-resume \
--public-access-block-configuration \
"BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true"
Загрузка файлов с правильными Content-Type
# Загрузка с установкой Content-Type и Cache-Control
aws s3 sync ./frontend/ s3://ivan-petrov-resume/ \
--delete \
--exclude "*" \
--include "*.html" \
--content-type "text/html; charset=utf-8" \
--cache-control "max-age=3600"
aws s3 sync ./frontend/ s3://ivan-petrov-resume/ \
--exclude "*" \
--include "*.css" \
--content-type "text/css" \
--cache-control "max-age=86400"
aws s3 sync ./frontend/ s3://ivan-petrov-resume/ \
--exclude "*" \
--include "*.js" \
--content-type "application/javascript" \
--cache-control "max-age=86400"
CloudFront Distribution
Полная конфигурация через CLI
# Шаг 1: Создаём OAC
OAC_ID=$(aws cloudfront create-origin-access-control \
--origin-access-control-config '{
"Name": "crc-s3-oac",
"SigningProtocol": "sigv4",
"SigningBehavior": "always",
"OriginAccessControlOriginType": "s3"
}' --query 'OriginAccessControl.Id' --output text)
# Шаг 2: Запрашиваем SSL-сертификат (ОБЯЗАТЕЛЬНО us-east-1)
CERT_ARN=$(aws acm request-certificate \
--domain-name resume.ivanpetrov.com \
--validation-method DNS \
--region us-east-1 \
--query 'CertificateArn' --output text)
echo "Добавьте CNAME-запись для валидации сертификата"
aws acm describe-certificate \
--certificate-arn $CERT_ARN \
--region us-east-1 \
--query 'Certificate.DomainValidationOptions[0].ResourceRecord'
# Шаг 3: Создаём CloudFront distribution
aws cloudfront create-distribution --distribution-config "{
\"CallerReference\": \"crc-$(date +%s)\",
\"Comment\": \"CRC Frontend\",
\"DefaultRootObject\": \"index.html\",
\"Enabled\": true,
\"HttpVersion\": \"http2and3\",
\"PriceClass\": \"PriceClass_100\",
\"Origins\": {
\"Quantity\": 1,
\"Items\": [{
\"Id\": \"S3-crc\",
\"DomainName\": \"ivan-petrov-resume.s3.us-east-1.amazonaws.com\",
\"S3OriginConfig\": {\"OriginAccessIdentity\": \"\"},
\"OriginAccessControlId\": \"$OAC_ID\"
}]
},
\"DefaultCacheBehavior\": {
\"TargetOriginId\": \"S3-crc\",
\"ViewerProtocolPolicy\": \"redirect-to-https\",
\"Compress\": true,
\"AllowedMethods\": {\"Quantity\": 2, \"Items\": [\"GET\", \"HEAD\"]},
\"CachedMethods\": {\"Quantity\": 2, \"Items\": [\"GET\", \"HEAD\"]},
\"CachePolicyId\": \"658327ea-f89d-4fab-a63d-7e88639e58f6\",
\"ResponseHeadersPolicyId\": \"\"
},
\"ViewerCertificate\": {
\"ACMCertificateArn\": \"$CERT_ARN\",
\"SSLSupportMethod\": \"sni-only\",
\"MinimumProtocolVersion\": \"TLSv1.2_2021\"
},
\"Aliases\": {\"Quantity\": 1, \"Items\": [\"resume.ivanpetrov.com\"]},
\"CustomErrorResponses\": {
\"Quantity\": 1,
\"Items\": [{
\"ErrorCode\": 403,
\"ResponsePagePath\": \"/index.html\",
\"ResponseCode\": \"200\",
\"ErrorCachingMinTTL\": 300
}]
}
}"
Bucket Policy для OAC
# Даём CloudFront доступ к S3
DIST_ARN="arn:aws:cloudfront::123456789012:distribution/EDXXXXXXX"
aws s3api put-bucket-policy --bucket ivan-petrov-resume --policy "{
\"Version\": \"2012-10-17\",
\"Statement\": [{
\"Sid\": \"AllowCloudFrontOAC\",
\"Effect\": \"Allow\",
\"Principal\": {\"Service\": \"cloudfront.amazonaws.com\"},
\"Action\": \"s3:GetObject\",
\"Resource\": \"arn:aws:s3:::ivan-petrov-resume/*\",
\"Condition\": {
\"StringEquals\": {
\"AWS:SourceArn\": \"$DIST_ARN\"
}
}
}]
}"
Route53 DNS
# Создаём A-запись (Alias) на CloudFront
aws route53 change-resource-record-sets \
--hosted-zone-id Z1234567890 \
--change-batch '{
"Changes": [{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "resume.ivanpetrov.com",
"Type": "A",
"AliasTarget": {
"HostedZoneId": "Z2FDTNDATAQYW2",
"DNSName": "d1234567890.cloudfront.net",
"EvaluateTargetHealth": false
}
}
}]
}'
Типичные проблемы
Проблема: 403 при обращении к /path (SPA routing)
Решение: Custom Error Response в CloudFront: 403 → /index.html с кодом 200.
Проблема: Сертификат не валидируется
Решение: Убедитесь, что CNAME-запись для валидации добавлена в DNS. Проверьте: aws acm describe-certificate --certificate-arn $CERT_ARN --region us-east-1.
Проблема: Старый контент после деплоя
Решение: Инвалидация CloudFront + проверьте Cache-Control заголовки.
aws cloudfront create-invalidation \
--distribution-id EDXXXXXXX \
--paths "/*"