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

За загрузку и получение картинок со сторонних сервисов в Ghost отвечают storage adapters. Я использую ghost-storage-adapter-s3 и это был мой первый опыт работы с AWS.

Что у нас получится

По завершению данные будут доступны по 3 httpS адресам. У меня это так:

  • https://s3.eu-central-1.amazonaws.com/s3.blog.amd-nick.me/2019/01/vk_-102092477_456241563.png
  • https://d13eyure4mvxeo.cloudfront.net/2019/01/vk_-102092477_456241563.png
  • https://s3.blog.amd-nick.me/2019/01/vk_-102092477_456241563.png

Обратите внимание, все ссылки работают по https:// (для работы с SSL нужны будут некоторые настройки). Как я понимаю, первая ссылка ведет напрямую на файл с S3 ведра в Франкфурте. Вторая — CDN (Нужен для поддержки SSL). Третья — CNAME алиас на вторую (Чтобы по красоте)

После загрузки изображения в пост, он автоматически будет загружен с тем же именем на Amazon S3, но удаляться таким же образом не будет (или не всегда)

Теория

Для меня было новым то, что S3 контейнеры, пути и объекты очень гибко настраиваются. Нужно будет настроить контейнер так, чтобы к нему был публичный точечный (только к файлам) рид онли доступ. По умолчанию контейнеры доступны для чтения и записи только владельцу и то через API. Через браузер файлы посмотреть не получится, пока не "расшарить их". Кстати и тут важно не наделать глупостей, ведь при неправильной настройке в худшем случае ваши файлы смогут удалить, а в лучшем будут видны все файлы в директории, а это не совсем безопасно

Такой точечный доступ мы настроим через 2 места:

  • В настройках контейнера сделаем его публичным для чтения файлов, если известен путь
  • Создадим "виртуального юзера AWS", которому дадим право на загрузку и удаление объекта. Это чисто мое название, как я это понимаю. В Amazon эта сущность называется IAM

Второе даст нам API ключ, который мы будем использовать в настройке S3 Storage Adapter. Даже если ключ "уведут", то не смогут причинить много ущерба хранилищу

Создаем хранилище (Bucket)

В консоли AWS на странице S3 жмем Create bucket. Делаем имя а-ля s3.site.com, регион почти любой, я выбрал Франкфурт (eu-central-1) и жмем сразу Create, не вдаваясь в подробности других страниц.

В properties самого контейнера включаем Static Website Hosting и запоминаем Endpoint адрес

Кстати, этот скриншот загрузился в S3

Допускаем публичный доступ к контейнеру (мы его ограничим)

Галочки быть не должно

Во вкладке Bucket policy сверху копируем значение ARN (У меня arn:aws:s3:::blat.test.com) и делаем примерно такую запись:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AddPerm",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::blat.test.com/*"
        }
    ]
}

Теперь объекты доступны по ссылке любому, кто ее получит. Для проверки можете загрузить в контейнер картинку и в ее свойствах будет Object URL

Делаем IAM пользователя (Виртуальный юзер)

Как я писал, им будет пользоваться наш блог для загрузки и удаления объектов, но у него не будет массовых действий, чтобы не навредить всему и вся

Сначала заходим на IAM > Policies > Create policy, где создадим "тип" прав доступа, который мы присвоим нашему IAM юзеру. На странице сразу переходим на вкладку json и, заменив в двух местах ARN, вставляем такое:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "s3:ListBucket",
            "Resource": "arn:aws:s3:::blat.test.com"
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "s3:PutObjectVersionAcl",
                "s3:DeleteObject",
                "s3:PutObjectAcl"
            ],
            "Resource": "arn:aws:s3:::blat.test.com/*"
        }
    ]
}

Сохраняем с любым именем, например s3-access-for-ghost-to-blat, чтобы понимать, что эта policy применима только к одному контейнеру

Теперь создаем юзера с этими правами. Заходим на страницу IAM > Users, жмем Add user, даем ему опять же любое имя, например, традиционное ghost-blat, ставим галочку "Programmatic access" и давим кнопку Next, где делаем attach нашей policy

Находим нашу policy на 3 вкладке, ставим возле нее галочку

Скипаем 3 и 4 вкладку, на 5 нам дадут наш Access key и Secret, как логин и пароль, с которым блог сможет работать с нашим S3 контейнером. Не забудьте сохранить до нажатия на Close. Они будут использоваться для настройки плагина

Делаем, чтобы файлы были доступны по SSL

Если ваш сайт работает по http:// без SSL, то можете сразу переходить к установке и настройке плагина.

Я хочу, чтобы мои картинки были доступны по httpS://, а сделать это по-простому можно было только через Amazon CloudFront

CloudFront это штука, которую можно прицепить к контейнеру и настроить CDN. CDN нам не нужна, а вот возможность настроить SSL для его эндпоинтов очень даже кстати. К тому же амазон умеет подписывать свои SSL. Прям как Lets Encrypt, но для корпов

Идем сюда, выбираем WEB. Видим кучу настроек. Часть из них:

  • Origin Domain Name: адрес, который был выдан нашему S3 контейнеру, когда мы включили Static Website Hosting. При нажатии оно предложит его
  • Origin Path это как "под путь". Путь к той папке, которую мы хотим считать корнем при доступе через домен. Я оставил пустым
  • Restrict Bucket Access запретит доступ к файлам по ссылке с S3 и они будут доступны только через CloudFront. Я оставил
  • Viewer Protocol Policy у меня редирект на https://
  • Allowed HTTP Methods Get, Head достаточно
  • Price Class выбрал чем поменьше, ибо мне вообще CDN не нужен
  • Alternate Domain Names (CNAMEs) вот это очень интересный пункт. Если у вас свой домен и вы определились, по какому поддомену будут доступны ваши файлы, то укажите его здесь. Что-то вроде s3.test.com
  • SSL Certificate. Если вы указали CNAME, тогда тут нужно переключить кнопку и сгенерировать сертификат. У меня тут была проблема, потому что я пытался сгенерировать сертификаты в eu-central-1, а оказалось, что их нельзя здесь использовать. Пришлось писать в поддержку, чтобы расширили лимит для us-east-1

Уже сейчас CloudFront выдал вам адрес, по которому доступны файлы контейнера по http://. Для проверки подставьте Domain Name, выданный клаудфронтом вместо домена, который выдался в Static Website Hosting

In Progress, но файлы уже доступны по адресу из 3 колонки, если приставить полный путь к файлу

Осталось открыть панель управления DNS записями вашего домена и добавить там CNAME (зеркало) запись с именем, указанным в Alternative Domain Names. В значение записи укажите Domain Name, который выдал CloudFront.

Установка и настройка адаптера

Она хорошо описана на странице репозитория проекта, там ничего сложного. Мой конфиг выглядит примерно так:

Я долго не вдуплял только что ввести в DEFAULT_REGION, остальное как-то понял

В S3_ASSET_HOST указываем имя той самой CNAME записи с https:// или адрес, выданный CloudFront, если не делали свой поддомен

Задавайте вопросы, всем отвечу.
Почитать еще всякие интересности можно у меня в t.me/uFeed