Analog Forest 🌳

Деплой SPA для бедных [EN translation is coming]

January 08, 2019

Уроки по фронтенду почти никогда не затрагивают релиз своего приложения в свет. Обычно весь экшн происходит на локальном дев-сервере с автоперезагрузкой и в редких случаях в конце статьи добавляется короткая глава о заливке своей поделки на now.sh или heroku.com. Оба сервиса весьма неплохи, но имеют ряд недостатков, перечисление которых выходит за рамки этого гайда.

Ancient train on a spectacular bridge
Photo by Jack Anstey on Unsplash. После этой статьи ваш pet-project попрет как паровоз на фото

Здесь мы поговорим о том, как развернуть свое приложение на серверах Амазона. С инфраструктурой, масштабирующейся до любого размера, и с оплатой по факту использования. Кроме низких цен на запросы, Амазон дарит новым пользователям год бесплатного использования в ограниченном количестве (более чем достаточном для того, чтобы начать свой стартап или просто поиграться с react/vue/angular).

AWS free tiers
Подробнее про лимиты бесплатного использования на https://aws.amazon.com/ru/free/

Подготовка

Регистрируем себе учетную запись на сайте AWS. Тут все просто, не отличается от обычных сайтов. Рекомендую двухфакторную аутентификацию, не пополняйте список охуительных историй про угон сайта/домена/пользовательских БД.

После регистрации аккаунта создадим пользователя из под которого будем деплоить. С основной учетки рулящей финансами это делать небезопасно, а для новой мы выдадим api-права только на S3. Для этого нужно зайти в IAM (Identity and Access Management), параллельно охренев от количества сервисов амазона:

AWS services list
У меня целиком в монитор не влезают, но я насчитал целых 133 штуки

Внутри переходим на вкладку Users, жмем «Add user». Придумываем небанальное имя своему новому другу и прожимаем галку «Programmatic access». Это означает, что работать из него можно будет только через API, без возможности зайти через интерфейс.

На следующем экране выбираем «Attach existing policies directly», в фильтре вводим s3 и выбираем из списка «AmazonS3FullAccess»:

Set AWS permissions
Set AWS permissions

Так мы назначаем этому пользователю права складывать файлы в хранилище S3. На третьем шаге еще раз проверяем все настройки и создаем пользователя. После этого нам покажут access key ID и secret access key, лучше сразу записать их в блокнотик: secret key больше увидеть не удастся.

Пацаны не дадут соврать: если любишь VS Code, в нем можно делать всё. Чтобы заливать свои приложения не выходя из консоли (а в последствии вообще командой npm) нам нужно скачать себе aws-cli — командную утилиту, позволяющую управлять большей частью амазоновских сервисов. Для её установки понадобится питоновский пакетный менеджер pip (и питон, ага).

> pip install awscli

Для ребят с виндой есть отдельный установщик (x64 / x32), но если уже есть pip, то с ним проще.

Перед тем как начинать работу с сервисами амазона через aws-cli необходимо настроить параметры подключения:

> aws configure

Command execution
Command execution

Настройка проходит в четыре этапа: надо указать access key ID и secret access key созданного в шаге 1.2 пользователя, регион по умолчанию (ближе всего к России eu-central-1, Франкфурт) и стандартный формат ответа. После того как настройка закончена, можете проверить работу командой «aws s3 ls»: при отсутствии ошибок остальные шаги должны работать.


Деплой

Наконец-то переходим к делу. В панели AWS открываем страницу S3 и жмем кнопку «Create bucket». Вводим имя (оно будет в url так что разрешены только соответствующие символы) и выбираем регион — EU Frankfurt. Остальное остается по умолчанию: логи, шифрование и права доступа здесь не понадобятся.

Закончив сборку своего творения пишем в консоли

> aws s3 sync .\build\ s3://YOUR-BUCKET-NAME

Command execution
С флагом dryrun можно предварительно посмотреть результат выполнения

Не забудьте подставить в команду нужную папку с приложением и имя своего бакета. Отдельный файл можно скопировать при помощи команды «aws s3 cp».

Поздравляю, ваше приложение уже в интернете, но похвастать перед одноклассниками пока не получится. При создании бакета мы не настроили его на раздачу файлов в интернете и не указали прав доступа. Это все не нужно, так как специально для сайтов есть более удобный способ доставки: Amazon CloudFront.

Чтобы вы могли настроить для своего сайта домен, прикрутить ssl-сертификат и вообще экономить на запросах (он кэширует по самое не хочу), в амазоне придумали CloudFront. Это CDN, занимающаяся доставкой контента в интернете до конечных пользователей. На главной странице сервиса жмем «Create Distribution» и выбираем «Get Started» под способом доставки «Web».

В поле «Origin Domain Name» выбираем недавно созданный бакет на S3, после этого поле «Origin ID» заполняется автоматически.

Configure AWS Cloudfront
В поле origin path ничего писать не нужно

Обязательно нажимаем на «Yes» в поле «Restrict Bucket Access». В появившихся после этого полях выбираем «Create a New Identity» для «Origin Access Identity» и «Yes, Update Bucket Policy» для «Grant Read Permissions on Bucket».

Configure AWS Cloudfront
Настройка важной хрени по картинкам? Все так делают

Последняя настройка должна обновить за нас политики доступа к хранилищу на S3, прописав туда доступ только учетке, привязанной к этому дистрибутиву CloudFront. Попозже мы это проверим.

В настройках кэша пока ничего менять не надо, единственное, можете включить автоматическое сжатие файлов при ответе на запросы с полем Accept-Encoding: gzip.

Configure AWS Cloudfront
Configure AWS Cloudfront

В разделе «Distribution Settings» можно поменять «Price Class» на «Use Only US, Canada and Europe» — так запросы будут дешевле. Вписываем имя корневого файла «Default Root Object» (обычно index.html) и жмем «Create Distribution». Остальные настройки трогать только по надобности.

Configure AWS Cloudfront
Почти готово

Осталось дождаться когда ваши файлы разойдутся по серверам конечной доставки и статус изменится на «Deployed». После этого ваше приложение будет доступно в самом настоящем интернете по url-адресу дистрибутива (ссылка, указанная в графе «Domain Name»).

Так как страниц в вашем красивом современном приложении ровно одна, то ошибки 404 (и для надежности 403) нужно перенаправлять на нее. Реакт-роутер же импортировали, пусть теперь отрабатывает. Для этого нужно выбрать ваш дистрибутив из списка и нажать кнопку «Distribution Settings». Там на вкладке «Error Pages» можно настраивать ответы на ошибочные запросы. Для каждого надо выбрать код ошибки, ввести время кэширования (про оптимальные параметры кэширования лучше почитать у гугла) и путь к вашей странице, которая обработает ошибку.

Configure AWS Cloudfront
Configure AWS Cloudfront

Пока ждем чуда можно проверить что там настроилось в S3: выбираем наше хранилище, переходим на вкладку « Permissions» и нажимаем «Bucket Policy».

Configure S3 bucket permissions
Configure S3 bucket permissions

Тут в формате JSON представлены права доступа для этого инстанса: доступ к нему разрешен только для учетки нашего дистрибутива CloudFront и только на чтение. Все взаимодействие пользователей с нашим сайтом будет происходить через CDN.


Финальные черты

Чтобы ваш сайт был доступен по красивому домену, прежде всего нужно этот домен купить. Сделать это можно или на все том же амазоне (судя по списку у них можно сделать все) или по рекомендации пацанов из интернета на сайте https://namecheap.com. Никогда не видел о нем отрицательных отзывов, чего не скажешь о других регистраторах, особенно российских.

После регистрации нужного домена переходим в панель управления к нему и добавляем CNAME запись, указывающую на url дистрибутива. При помощи этой записи браузеры будут получать информацию именно из вашего хранилища:

Configure DNS routing
Так это выглядит в панели управления namecheap

На этом этапе вам необходимо выбрать, хотите ли вы, чтобы сайт был доступен на поддомене www или нет: лучше придерживаться одного варианта, а со второго переадресовывать пользователей. В интернете приводят мнения, что использовать поддомен удобнее и грамотнее с технической точки зрения, но мне больше нравится без него. Решать вам: если хотите использовать www, то в CNAME записи нужно поставить «www» в поле host. Для чистого домена ставьте «@».

Чтобы явно переадресовать пользователя, заходившего по www., на чистый домен (или наоборот), нужно добавить еще одну запись в DNS. Тип записи «URL Redirect Record», в поле host — поддомен с которого переадресовать, в поле value — домен, куда переадресовать. Здесь сразу укажите домен с протоколом https, чтобы пользователя не приходилось перенаправлять с http потом.

Configure DNS routing
Configure DNS routing

Unmasked означает, что перенаправление явное, в браузере изменится адрес.

Последний шаг этой эпопеи — настройка сертификата для того, чтобы сайт нормально работал по https. Здесь опять есть несколько вариантов: прикрутить к CloudFront бесплатный сертификат от Let’s Encrypt и настроить его автоматическое обновление (из статьи на медиуме можно узнать конкретные шаги), либо получить сертификат от амазона. К этому шагу вы должны были заметить, что все амазоновское между собой круто интегрировано. Единственный минус получения сертификата у них — непонятные проблемы с лимитом на сертфикаты: когда я пытался создать сертификат мне постоянно выкидывало ошибку. Запрос в техподдержку об увеличении лимита количества сертификатов сделал свое дело, но заняло это почему-то целых два дня. В самой поддержке мне сказали, что это случается достаточно часто, так что возможно вам тоже придется писать просьбу на поднятие лимита.

На главной странице Certificate Manager вам нужно выбрать регион US East (N. Virginia) — это важно, CloudFront работает только с сертификатами, выданными в этом регионе.

Create new certificate
Изменить текущий регион можно в правом верхнем углу страницы

После этого нажать на кнопку «Get started», ввести имя своего зарегистрированного домена и выбрать, как вы хотите подтверждать свое владение им (ссылка в почте или новая днс запись). После подтверждения по ссылке сертификат готов и вы можете подключить его в CloudFront.

Выбираем из списка ваш дистрибутив, заходим в настройки при помощи кнопки «Distribution settings». На первой же вкладке нажимаем «Edit» и вносим следующие изменения: ваш домен в поле «Alternate Domain Names (CNAMEs)», «Custom SSL Certificate» и выбираем из списка выданный вам амазоном сертификат.

Add certificate to cloudfront
Add certificate to cloudfront

Для сохранения настроек жмем «Yes, Edit».

Change protocol handling
Change protocol handling

Переходим на вкладку «Behaviors», выделяем единственный пункт в списке и заходим в настройки по кнопке «Edit».

В поле «Viewer Protocol Policy» меняем поведение на «Redirect HTTP to HTTPS», это будет перенаправлять всех посетителей на версию https, зашифрованную нашим сертификатом.

P.S. после этих настроек можно запихнуть все нужные команды в package.json:

"scripts": {
    "start": "...",
    "test": "...",
    "build": "...",
    "predeploy": "npm run build",
    "deploy": "aws s3 sync .\\build\\ s3://YOUR-BUCKET-NAME",    "postdeploy": "aws cloudfront create-invalidation \        --distribution-id YOUR-DISTRIBUTION-ID \        --paths /*"  }

Теперь команда deploy предварительно пересобирает ваш проект (predeploy), выкладывает его на S3, после чего создает новую инвалидацию на CloudFront (postdeploy) для того, чтобы CDN обновили файлы, которые необходимо отдавать по запросу.


На этом все, надеюсь эта статья принесет вам пользу.


by Pavel Prokudin. I write about web-development and modern technologies. Follow me on Twitter