Что такое статический сайт
Статический сайт -- это набор HTML, CSS и JavaScript файлов, которые отдаются браузеру как есть, без серверной обработки. В отличие от динамического сайта (PHP, Node.js), не нужен сервер приложений -- достаточно хранилища файлов и HTTP-сервера.
Для CRC это идеально: резюме -- это статические файлы, и облачное хранилище может выступать веб-сервером.
Почему облачное хранилище, а не EC2/VM
| Параметр | Хранилище (S3/Blob/GCS) | Виртуальная машина |
|---|---|---|
| Стоимость | ~$0.01/месяц | ~$5-10/месяц |
| Управление | Нулевое | Обновления, патчи, мониторинг |
| Масштабирование | Автоматическое | Ручное |
| Безопасность | Управляемая | Ваша ответственность |
| Подходит для | Статических файлов | Динамических приложений |
AWS: S3 Static Website Hosting
Шаг 1: Создание бакета
# Создаём бакет (имя должно быть глобально уникальным)
aws s3 mb s3://ivan-petrov-resume --region us-east-1
# Включаем Static Website Hosting
aws s3 website s3://ivan-petrov-resume \
--index-document index.html \
--error-document error.html
Шаг 2: Настройка публичного доступа
# Снимаем Block Public Access (нужно для прямого доступа)
aws s3api put-public-access-block \
--bucket ivan-petrov-resume \
--public-access-block-configuration \
"BlockPublicAcls=false,IgnorePublicAcls=false,BlockPublicPolicy=false,RestrictPublicBuckets=false"
# Добавляем Bucket Policy для публичного чтения
aws s3api put-bucket-policy --bucket ivan-petrov-resume --policy '{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::ivan-petrov-resume/*"
}
]
}'
Важно: После настройки CloudFront (в следующей статье) мы заменим публичный доступ на OAI/OAC, чтобы S3 был доступен только через CDN.
Шаг 3: Загрузка файлов
# Загрузка всех файлов
aws s3 sync ./cloud-resume/ s3://ivan-petrov-resume/ \
--delete \
--cache-control "max-age=86400"
# Проверка
aws s3 ls s3://ivan-petrov-resume/
Шаг 4: Проверка
Откройте URL вида: http://ivan-petrov-resume.s3-website-us-east-1.amazonaws.com
URL зависит от региона. Формат:
<bucket>.s3-website-<region>.amazonaws.com
Azure: Blob Static Website
Шаг 1: Создание Storage Account
# Создаём группу ресурсов
az group create --name crc-resources --location westeurope
# Создаём Storage Account (имя: только буквы и цифры, 3-24 символа)
az storage account create \
--name ivanpetrovresume \
--resource-group crc-resources \
--location westeurope \
--sku Standard_LRS \
--kind StorageV2
Шаг 2: Включение Static Website
# Включаем Static Website на Storage Account
az storage blob service-properties update \
--account-name ivanpetrovresume \
--static-website \
--index-document index.html \
--404-document error.html
Шаг 3: Загрузка файлов
# Загружаем файлы в контейнер $web
az storage blob upload-batch \
--account-name ivanpetrovresume \
--source ./cloud-resume/ \
--destination '$web' \
--overwrite
# Проверка
az storage blob list \
--account-name ivanpetrovresume \
--container-name '$web' \
--output table
Шаг 4: Проверка
URL вида: https://ivanpetrovresume.z6.web.core.windows.net
Azure автоматически включает HTTPS для static website endpoint.
GCP: Cloud Storage Hosting
Шаг 1: Создание бакета
# Создаём бакет (имя должно совпадать с доменом, если планируется DNS)
gsutil mb -p PROJECT_ID -l us-central1 gs://ivan-petrov-resume
# Настраиваем как static website
gsutil web set -m index.html -e error.html gs://ivan-petrov-resume
Шаг 2: Настройка публичного доступа
# Делаем все объекты публичными
gsutil iam ch allUsers:objectViewer gs://ivan-petrov-resume
Шаг 3: Загрузка файлов
# Загрузка файлов
gsutil -m cp -r ./cloud-resume/* gs://ivan-petrov-resume/
# Установка Content-Type для HTML файлов
gsutil setmeta -h "Content-Type:text/html" gs://ivan-petrov-resume/index.html
gsutil setmeta -h "Content-Type:text/css" gs://ivan-petrov-resume/style.css
# Проверка
gsutil ls gs://ivan-petrov-resume/
Шаг 4: Проверка
URL: http://storage.googleapis.com/ivan-petrov-resume/index.html
GCP Cloud Storage не поддерживает HTTPS для custom domains напрямую -- нужен Load Balancer или Firebase Hosting.
Сравнение подходов
| Параметр | AWS S3 | Azure Blob | GCP Storage |
|---|---|---|---|
| Включение хостинга | aws s3 website |
az storage blob service-properties update |
gsutil web set |
| Контейнер файлов | Весь бакет | $web контейнер |
Весь бакет |
| HTTPS | Нет (нужен CloudFront) | Да (автоматически) | Нет (нужен LB) |
| Custom domain | Через Route53 + CloudFront | Через CDN | Через LB |
| URL формат | bucket.s3-website-region.amazonaws.com |
account.z6.web.core.windows.net |
storage.googleapis.com/bucket/ |
| Стоимость хранения | $0.023/GB/мес | $0.018/GB/мес | $0.020/GB/мес |
Content-Type и Cache-Control
Правильные заголовки
Облачное хранилище может неправильно определить Content-Type. Установите явно:
# AWS: при загрузке с правильными типами
aws s3 sync ./cloud-resume/ s3://ivan-petrov-resume/ \
--exclude "*" \
--include "*.html" \
--content-type "text/html" \
--cache-control "max-age=3600"
aws s3 sync ./cloud-resume/ s3://ivan-petrov-resume/ \
--exclude "*" \
--include "*.css" \
--content-type "text/css" \
--cache-control "max-age=86400"
aws s3 sync ./cloud-resume/ s3://ivan-petrov-resume/ \
--exclude "*" \
--include "*.js" \
--content-type "application/javascript" \
--cache-control "max-age=86400"
Рекомендуемые Cache-Control
| Тип файла | Cache-Control | Причина |
|---|---|---|
| HTML | max-age=3600 (1 час) |
Может обновляться часто |
| CSS/JS | max-age=86400 (1 день) |
Обновляется реже |
| Изображения | max-age=604800 (7 дней) |
Обновляется редко |
Типичные проблемы и решения
Проблема: 403 Forbidden
Причина: Публичный доступ не настроен или заблокирован.
Решение AWS: Проверьте Block Public Access и Bucket Policy.
Решение Azure: Static website автоматически публичный, проверьте что файлы в $web.
Проблема: Пустая страница
Причина: Неправильный Content-Type (например, application/octet-stream вместо text/html).
Решение: Явно укажите Content-Type при загрузке.
Проблема: Старый контент после обновления
Причина: Кэширование браузера или CDN.
Решение: Используйте версионирование файлов (style.v2.css) или инвалидацию кэша CDN.