В этой статье хочу кратко рассказать о том, как захостить свою веб-аппликацию на CDN от Amazon. Это может быть интересно всем, кто хочет улучшить доступ к своему ресурсу, а именно ускорить загрузку статического контента пользователями.
Часто оптимальным решением является использование сети Распространения Контента (CDN). Статическим контентом здесь может быть как побеленная JavaScript Аппликация (React или Angular), так и изображение или статический HTML. В этой статье будем оперировать AWS S3 (для хранения и хостинга), CloudFront (как CDN) и функционалом DNS-провайдера (может быть любой), в нашем случае это CloudFlare. Будем использовать TLS/SSL сертификат от Cloudflare для того, чтобы ресурс работал на HTTPS (с поддержкой Cloudflare «Full Strict» режима).
Задача кажется простой и много ресурсов по освещению подобного, однако, как оказалось, есть много подводных камней, и аналогичный контент часто устаревший.
Здесь не будем рассматривать создание и билд JS аппликации, создание S3 бакета (или «ведра» на украинском языке), заливку контента в бакет или регистрации DNS-домена.
HTTP на S3
Итак, создаем S3 бакет и заливаем сбилденный код туда, в корень. Однако здесь есть нюанс – ограничение от Amazon: бакет должен иметь имя такое же, как домен (поддомен). К примеру,
если планируется разместить билд на домене my . react-app . com, то и название бакета должно быть my . react-app . com.
Далее в свойствах бакета (вкладка Properties) следует включить Static website hosting. Ниже, в поле Index Document, необходимо указать index файл (index.html обычно).
Сохраняем настройки и переходим к вкладке доступа (Permissions).
Здесь нам нужно отключить блокировку доступов, если она активна (Block public access).
В Bucket Policy (Политика доступа) нам нужно предоставить доступ для CloudFront. Чтобы упростить задачу, предоставим доступ ко всем сервисам AWS (потом это можно перенастроить).
В поле для JSON нужно скопировать следующее:
{ "Version" : "2012-10-17" , "Id" : "Policy1638279142165" , "Statement" : [ { "Sid" : "Statement1" , "Effect" : "Allow" , "Principal" : { "AWS " : "*" } , "Action" : "s3:GetObject" , "Resource" : "arn:aws:s3:::my.react-app.com/*" } ] }
где в строке «Resource»: «arn:aws:s3:::my» . react-app . com/*»
« my . react-app . com» нужно заменить именем этого бакета.
Сохраняем настройки и стараемся получить доступ к аппликации через HTTP. Для этого на вкладке свойств бакета (Properties) в поле Static website hosting переходим по ссылке, указанной под пунктом «Bucket website endpoint».
На этом этапе мы должны иметь доступ к нашему ресурсу под сгенерированным доменом через HTTP. Если с этим возникли проблемы, то следует попытаться пройтись по предварительным настройкам еще раз, прежде чем двигаться дальше.
SSL/TLS сертификат
Чтобы ресурс работал через HTTPS, нужно использовать сертификат, сгенерированный для требуемого домена. Если на AWS уже есть сертификат (например, если домен на Route 53), этот шаг можно пропустить.
Для менеджмента сертификатов в AWS есть сервис Certificate Manager (ACM). Заходим туда и выбираем опцию запроса сертификата (Request certificate). Далее выбираем опцию публичного сертификата (Request a public certificate).
Здесь есть первый нюанс: для того чтобы сертификат можно было использовать в Cloudfront, его нужно добавлять именно в зоне доступности «N.Virginia» (us-east-1), что совсем не интуитивно.
Там заполняем название домена:
И способ валидации:
Выбираем DNS-валидацию, ведь именно этот способ рекомендован. Нажмите Request, чтобы создать запрос на получение сертификата.
После этого сертификат появится в списке сертификатов со статусом «Ожидающий валидации» (Pending validation). Чтобы валидировать его, нужно создать DNS-запись согласно сгенерированным значениям:
Мы подтвердили принадлежность текущего ресурса к указанному домену (а значит и сертификату).
Итак, добавляем соответствующую CNAME запись в DNS (в нашем случае в Cloudflare):
Через некоторое время наш сертификат будет валидирован и получит статус «Issued».
Cloudfront
Cloudfront – это CDN сервис от Amazon, который с помощью глобально распределенных прокси-серверов кэширует контент, у нас – составляющие аппликации. Поэтому нам нужно настроить дистрибутив для распределения с источником данных в созданное S3 ведро (bucket).
В Distributions выбираем Create и заполняем Origin domain.
Здесь еще один совсем не интуитивный момент: когда мы будем вводить название бакета, нам подтянется наш S3 ресурс. Однако это не то, что нам нужно.
В это поле нужно вставить URL, по которому мы раньше через HTTP имели доступ к нашему бакету. Чтобы его получить, идем в «Свойства» нашего бакета (Bucket Properties) и копируем адрес с поля website endpoint. Вставляем его без http:// и без слеша в конце.
К примеру, в нашем случае, в поле Origin domain при создании дистрибутива у нас будет подсказка:
« my . react-app . com . s3 . amazonaws . com » (заканчивается «s3 . amazonaws . com»)
а нужно:
« my . react-app . com . s3-website-eu-west-1 . amazonaws . com»
Далее ищем поле Alternate domain name . Здесь нужно указать домен (название бакета), например my . react-app . com .
И выбрать созданный сертификат.
Все остальные поля оставляем без изменений и создаем дистрибутив.
Сначала дистрибутив получит статус deploying, и когда станет готовым к использованию, статус изменится на Enabled.
На этом этапе наш ресурс должен быть доступен через нужный HTTPS на CDN Amazon. Чтобы убедиться в этом, нужно перейти на URL, указанный в деталях нового дистрибутива:
Финальный штрих
Теперь, чтобы данная аппликация работала под нашим доменом, нужно создать соответствующую DNS запись, в которой мы впишем, что за контентом для указанного домена следует обратиться к настроенному выше дистрибутиву Cloudfront ( Distribution domain name ). Поскольку дистрибутив доступен по URL, используем ту же запись CNAME.
Чтобы DNS запись вступила в действие, нужно определенное время.
DNS-провайдер Cloudflare
Если все прошло хорошо, и все остальные DNS записи отвечают требованиям end-to-end HTTPS шифрования, можно включить режим «Full (strict)».
Index файл не найден
Если на каком-то этапе вместо приложения открывается XML с перечнем файлов в ведре, то вероятно, что cloudfront не знает, какой индекс файл использовать. Чтобы исправить это, можно настроить путь к индексу файла (Origin path) в Cloudfront дистрибутиве.