MidПрактика3 min

Хостинг статического сайта

Размещение HTML-резюме на S3, Azure Blob Storage и GCP Cloud Storage с настройкой статического хостинга

Что такое статический сайт

Статический сайт -- это набор 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.

Проверь себя

Почему рекомендуется устанавливать разные Cache-Control для HTML и CSS файлов?

Какой контейнер Azure Blob Storage используется для файлов статического сайта?

Что нужно сделать в AWS S3 перед настройкой Bucket Policy для публичного доступа?

Какой облачный провайдер автоматически предоставляет HTTPS для статического сайта без дополнительной настройки CDN?

Почему для CRC рекомендуется использовать облачное хранилище, а не виртуальную машину?