coverImage.svg

Strapi V4をHerokuとS3にデプロイし、安くて自由なHeadlessCMS環境を手に入れる。

本記事ではStrapi v4をherokuにデプロイする流れを説明します。セルフホスティング型の利点を生かし、安価で多機能なHeadlessCMS環境を手に入れましょう。ローカル開発環境の構築方法と、本番環境の構築をガイドします。画像保存のストレージはAWS-S3を利用し、ホスティング先はheroku、記事保存のDBにはPostgreSQLを使用します。
公開日2022.01.26
更新日2022.02.01

はじめに

この記事は、HeadlessCMSであるStrapi(v4)の導入方法をまとめた 技術記事 です。下記の方を想定して記述しています。

対象読者

  • HeadlessCMSを使ってサイトを構築したい人。
  • HeadlessCMSを毎月「安い」料金で運用したい人。
  • Strapi v4の導入の流れを追いたい人。それにより競合のHeadlessCMSと比較しながら、初期導入コストをざっくり見積もりたい人。
  • Strapi「V4」の導入に詰まったので、問題解決したい人。V4のドキュメントがアップデートされていなく、困っている。

要求知識

  • ターミナル(CUI)が使える。
  • herokuの初期設定ができる。
  • AWS S3の初期設定ができる。
  • Postgresqlまたはそれに類するRDBの設定の知識。

Strapiとは?〜安くて多機能なHeadlessCMS

Strapiはセルフホスティング型のHeadlessCMSです。
HeadlessCMSは初期構築が不要なクラウド型と、自分で初期設定を行うセルフホスティング型の2つに大別でき、Strapiは後者にあたります。
初期導入のコストはかかるものの、月々の支払いはホスティング代のみと安く済みます。競合製品の中も、頭ひとつ抜けた優れたUXと多機能さを持っています。メディアやブログの運用はもちろん、バックエンドサーバーにも使えますので、アプリのプロトタイピングやモデリングにも最適です。
2021年12月にV4へのメジャーアップデートが行われ、より快適なUIや開発環境に一新されました。
💡 補足:クラウド型・セルフホスティング型とは?
  • クラウド型HeadlessCMS ノーコードで初期設定ができるものの、ランニングコストが高い。大体5000円/月からのスタート。法人で運用するには手軽な価格帯だが、個人の場合、高い費用に。サービスによってはフリープランがあるができることに制限が。
  • セルフホスティング型HeadlessCMS 初期費用のコストと知識が求められるものの、ランニングコストはホスティング料金のみなので、月々の支払いは安く済む。herokuの最安プランであれば$7(1000円程度)。また拡張性も申し分なく、クラウド型の高価格プランに匹敵するオプションを利用できる。

Strapiのランニングコスト

ホスティングにはheroku、画像保存ストレージにはAWS-S3を利用。月10,000PVのアクセスを想定すると、毎月1,000円程度で済む計算です。
利用サービス① heroku
  • 合計 70USD(980円)
    • コンテナ - Hobby ($7/dyno/月)
    • DB(Postgresql) - Hobby Dev Basic (無料)
      • 10000行まで無料
      • 同時接続20
利用サービス② AWS-S3
  • 前提 画像保存量 5GB/月の読取回数 100万回/月の書込回数 1000回
  • 合計 0.50USD (70円)
    • 毎月の保存金額 0.13 USD(5GB * 0.025USD/GB )
    • 画像読取 0.37 USD (1,000,000回 * 0.00000037USD/回 )
    • 画像書込 0.0047 USD (1000回 * 0.00000037USD/回 )

本記事のゴール

この記事で何を作るのかについて、簡単に概要を説明します。

できるようになること

  • Dockerを使って、ローカルでStrapiV4の開発(設定)ができる。
  • HerokuにStrapiをデプロイする。
  • HerokuにStrapiを本番モードで起動する。
  • AWS-S3にStrapiのストレージを設定できる。
  • StrapiV4でGraphQLを利用できるようにする。

やらないこと

  • Strapiに接続するフロントエンドの開発

最終完成図

上記のゴールを満たす最終完成図は下記です。この完成図になるように解説していきます。
articles-1-content-1.svg
ローカル開発環境
  • Docker環境
    • Strapiコンテナー
      • nodeコンテナーをベースに作られている。nodeでstrapiが起動しているコンテナー
    • Postgresql コンテナー
      • Strapiから接続するDBコンテナー
  • AWS S3(設置は任意)
    • Strapiからアップロードしたメディアを保存する。
    • 設置は任意。開発環境で設置しなくてもいいが、本番と近しい環境にしておいた方が何かと便利なので設置。(エラー等があった場合気軽にローカルで検証できるため)
本番環境
  • heroku
    • Dyno
    • heroku PostgreSQL
  • AWS S3

必要な事前準備

Dockerのインストール
AWS S3のBucket作成と、アクセス権限の発行
  • AWSのS3にアクセスし、開発用のbucketと、本番用のbucketを作成します、
  • StrapiからアクセスするIAMを作成します。
    • 開発用bucketにアクセスできる、ACCESS_KEYとACCESS_SECRETを控えます。
    • 本番用のbucketにアクセスできる、ACCESS_KEYとACCESS_SECRETを控えます。
  • 具体的なやり方は下記記事等をご参考ください
Herokuの契約

ローカル開発環境をつくる

この項目では、ローカル開発環境の構築方法を説明していきます。

Docker-imageを作る

Dockerfileをcloneします。

git clone https://github.com/hanzochang/strapi-v4-dockerfile.git
  • ❗注意:これは非公式のDockerfileです 公式がStrapi「v4」に対応したdocker-imageを出していないため、issue等を参考に筆者が改築しました。

docker-imageをビルドします。

docker-compose up
しばらく時間がかかります。パッケージのインストール、ファイル生成、DBのマイグレーションを実施します。
contentImage002.jpg
strapiコンテナから上記のような出力がされていれば起動成功です。 止めたい場合は、ctrl + cでストップすることができます。次回以降も、同じコマンドで起動することができます。

ローカル開発環境のStrapiにアクセスします。

http://localhost:1337/admin にアクセスすると管理者ユーザーの登録画面が起動します。ローカルの管理者ユーザーを作成し、ログインをします。最後のチェックボックスをチェックすると、Strapi開発チームからのメールを受け取ることができます。
contentImage002.jpg
この登録が完了すると、Strapiのダッシュボードが表示されます。
contentImage004.jpg
この画面が表示されれば、無事ローカル開発環境でのStrapiの起動完了です👏

テーブルを作りレコードを追加する

ここまでの操作でローカルでStrapiを起動することができました。
ですが、テーブルやレコードは空です。この状態だと説明に支障があるので、以下の解説でテーブルとレコードの作成を行います。

テーブルを作る

ContentTypeBuilderを使って、テーブルを作ってみましょう。「Create a collection type」から、新しいテーブルを作成することができます。
contentImage005.jpg
テーブル作成後は、カラムを追加することができます。カラムに対応した入力インターフェースを設定することができます。カラムにはJSONを選ぶことができたりと、柔軟なテーブル設計を行うことができます。
contentImage006.jpg
カラムを設定した後に「save」を押すと、Strapiが再起動し、DBのマイグレーションが反映されます。
contentImage007.jpg

最初のデータを入力する

ContentManagerから、データの入力をします。
contentImage009.jpg
最後「publish」を押すことを忘れないでください。 後述のGraphQLでの読み出し時に必要です。(publishではないレコードはcollectionの読み出し時に出力されないという仕様があるため)
💬 余談:テーブルを追加した時に何が起こっているのか
Strapi上での変更は、すぐにDBに反映されました。 実際には下記のようなことが起こっています。
DB更新の流れ
contentImage010.jpg
  • GUIでテーブルの追加をする
  • 更新がsrc/配下のファイルが更新される
  • strapiが再起動する。再起動が走るタイミングでDBのマイグレーションが走る
    • strapiはapp/src/配下の変更をwatchし続けていて変更があれば再起動するようになっている
  • DBが更新される。 
この流れを利用すると
GUIを使わなくとも、直接src配下のファイルを操作することでDBのマイグレーションを走らせることができます。 GUIを通さず素早くDBを更新したい場合は、ファイルの直接操作をするのも手です。
なお本番では
今回説明したテーブル追加(Content-TypeBuilder)は、本番ではDisableになっています。本番環境ではGUIから直接DBの変更やファイルの変更ができないようになっています。
そのため、開発はローカル環境で行います。
GUIコンソールまたは直接ファイルの編集を行うことで、ファイルを変更し、DBのマイグレーションを進めます。そのソースコードを本番にPUSHし、本番に反映する、というのが開発の流れです。

AWSのS3設定する

メディアファイルをAWS-S3にアップロードできるように設定します。
# app/配下で実行すること 
yarn add @strapi/provider-upload-aws-s3
./config/plugins.js にS3の設定値を書き込みます。
module.exports = ({ env }) => ({
  upload: {
    provider: 'aws-s3',
    providerOptions: {
      accessKeyId: env('AWS_ACCESS_KEY_ID'),
      secretAccessKey: env('AWS_ACCESS_SECRET'),
      region: env('AWS_REGION'),
      params: {
        Bucket: env('AWS_BUCKET_NAME'),
      },
    },
  },
}); 
./config/middlewares.jsに設定値を書き込みます。
module.exports = ({ env }) => [
  "strapi::errors",
  {
    name: "strapi::security",
    config: {
      contentSecurityPolicy: {
        useDefaults: true,
        directives: {
          "connect-src": ["'self'", "https:"],
          "img-src": ["'self'", "data:", "blob:", `${env("CDN_BASE_URL")}`],
          "media-src": ["'self'", "data:", "blob:", `${env("CDN_BASE_URL")}`],
          upgradeInsecureRequests: null,
        },
      },
    },
  },
  "strapi::cors",
  "strapi::poweredBy",
  "strapi::logger",
  "strapi::query",
  "strapi::body",
  "strapi::favicon",
  "strapi::public",
];
DockerfileにAWSのKeyを設定します。
version: "3"
services:
  strapi:
    image: strapi/strapi
    environment:
      DATABASE_CLIENT: postgres
      DATABASE_NAME: strapi
      DATABASE_HOST: postgres
      DATABASE_PORT: 5432
      DATABASE_USERNAME: strapi
      DATABASE_PASSWORD: strapi
      AWS_ACCESS_KEY_ID: # 開発用BucketにアクセスできるIAMのKEY
      AWS_ACCESS_SECRET: # 開発用BucketにアクセスできるIAMのSECRET
      AWS_REGION: # AWSのREGION
      AWS_BUCKET: # 開発用Bucket名
      CDN_BASE_URL: # S3ベースURL 例:https://s3.ap-northeast-1.amazonaws.com/example-example/
動作確認をします。
dockerの再起動をし、アップロードできることを確認します。
# ctrl + cで既存のプロセスを終了後、下記コマンド入力でもう一度起動
docker-compose up

設定が正しいかを確認

ファイルのURLを確認し、正しいURLでアップロードされていることを確認します。
contentImage012.jpg

GraphQLを設定する

Strapiにgraphqlをインストールします。 初期状態ではgraphqlでデータを取得できません。 公式の提供するプラグインのインストールが必要です。
@strapi/plugin-graphqlのインストール
docker上でのインストールが必要なので、コンテナに入ります。
docker-compose run strapi bash
コンテナのbashで、下記コマンドを実行します。
yarn add @strapi/plugin-graphql
GraphQLの読取権限の付与
次に、アクセス権限の設定を行います。
初期設定では、外部からの読取書込権限がありませんので、権限を付与します。
Settings>User&Permissions plugin>Roleから、Pluginを選択します。
contentImage013.jpg
前述の「データモデルを作る」で作成したモデルを選び、findとfindOneにチェックボックスをオンにし「save」します。
contentImage014.jpg
GraphQLの実行をテスト
http://localhost:1337/graphql にアクセスすると、GraphQLのplaygroundが起動します。
contentImage015.jpg
autocompleteがききますので、導かれるままにクエリを組み上げていくことで、データを取得することができるようになります。
contentImage016.jpg
また、特定のモデルのコレクションを取得したい場合は下記のクエリで取得できます。
contentImage017.jpg
クライアントからアクセスするエンドポイント
なおクライアント側からリクエストするエンドポイントも、http://localhost:1337/graphql になります。

以上がローカル開発環境の解説でした。

大きく下記の4点を行いました。
ここまででやったことの復習
  • Docker-imageを作り、Strapiを起動する
  • 最初のテーブルを作りレコードを追加する
  • AWSのS3設定する
  • GraphQLを設定する
ローカルで開発をすすめていきましょう
ここまでの流れでローカルで開発を進めることができるようになりました。 自分の作りたいテーブルを追加していき、gitにcommitしていきながら開発を進めていきます。 何の特殊なことはない、通常通りの開発です。

本番用環境を作る

この項目から、ローカルで開発したStrapiをherokuにpushし、本番環境として構築していく方法を解説します。

herokuのコンテナの用意をする

ブラウザでherokuにログインしておきます。
https://id.heroku.com/login でログインを済ませておきます。
CLIでherokuにログインします。
ローカル開発環境で作成した作業ディレクトリの「app/」に移動し、herokuにログインします。
heroku login
URLが出力されるので、先ほどログインしたブラウザでアクセスします。その後CLIでのログインが完了となります。
herokuのプロジェクトを作成します。
herokuのプロジェクトを作成します。
heroku create あなたのプロジェクト名
https://dashboard.heroku.com/apps/ にアクセスすると、プロジェクトが生成されていることが確認できます。
contentImage018.jpg
なおこのタイミングでは料金は発生していません。

herokuでDBの用意をする

herokuにPostgresqlを設置します。
herokuにPostgresqlを設置します。1行ですぐに用意できます。
heroku addons:create heroku-postgresql:hobby-dev
PostgreSQLの設置が成功したかを確認する
設置を確認するには、下記コマンドをリクエストします。
heroku config
ここで、下記のようなパラメータが返却されていれば設置は完了です。
DATABASE_URL: postgres://ebitxebvixeeqd:dc59b16dedb3a1eef84d4999sb4baf@ec2-50-37-231-192.compute-2.amazonaws.com: 5432/d516fp1u21ph7b
💡herokuのwebサイト上でも設置を確認できます。
contentImage019.jpg

herokuに環境変数を設定する

下記の手順で、ConfigVars(環境変数入力フォーム)に移動し、キーと値を入力します。
contentImage020.jpg
各種設定値の解説
  • AWS_ACCESS_KEY_ID
    • 本番用S3へのアクセス権限を持つIAMのKEY_IDを入力します。
  • AWS_ACCESS_SECRET
    • 本番用S3へのアクセス権限を持つIAMの本番用ACCESS_KEYを入力します。
  • AWS_BUCKET
    • 本番用S3のバケット名を入力します
  • AWS_REGION
    • 本番用S3のRegionを入力します。
  • CDN_BASE_URL
  • DATABASE_URL
    • データベースURLが設定されています。
  • MY_HEROKU_URL
    • 自身がホストするURLを設定します。
  • NODE_ENV
    • productionと設定します。

Strapiに本番DBの設定をする

本番用のDBの設定をします。「app/src/config/env/production」にdatabase.jsを設置し、下記の内容を書き込みます。herokuの環境変数の「DATABASE_URL」から、各パラメータをパースできる設定にします。
const parse = require("pg-connection-string").parse;
const config = parse(process.env.DATABASE_URL);

module.exports = ({ env }) => ({
  connection: {
    client: "postgres",
    connection: {
      host: config.host,
      port: config.port,
      user: config.user,
      database: config.database,
      password: config.password,
      ssl: {
        rejectUnauthorized: false,
      },
    },
    debug: false,
  },
});
💡 余談:NODE_ENV production専用のconfigファイルを作る
Strapiの環境変数のNODE_ENVをproductionの状態で起動すると、本番モードで起動することができます。
本番モード用のconfigは別に記述することができ、 「app/src/config/env/production」 配下にファイルを設置することでproduction専用のconfigを設定することができます。ここに設置されたconfigを最優先で読み込む処理になります。

本番デプロイ

上記の追加をcommitし
git add .
git commit -m "Update database config"
herokuにpushします。
git push heroku main
push終了後、herokuを開きます。
heroku open
設定の不備等で起動できていない場合があります。その際は下記コマンドでログを確認し、エラーの原因を突き止めて修正します。
heroku logs --tail

GraphQLの公開権限の設定

ローカル環境で設定した公開権限の設定を本番でも行います。 (公開権限の設定は、ファイルではなくDBに保存されるので、ローカルとは別に本番でも設定が必要となります。)
contentImage013.jpg
前述の「データモデルを作る」で作成したモデルを選び、findとfindOneにチェックボックスをオンにし「save」します。
contentImage014.jpg
production環境で起動した場合、graphqlのplaygroundは立ち上がりません。下記のようにローカルで立ち上げたplayground経由で、graphqlをテストしてください。(他のgraphqlツールでも可)

本番起動時の確認事項

S3にアップロードできるかを確認
S3にメディアファイルをアップロードできているか確認してください。
contentImage021.jpg
レコード作成できるかの確認
レコードを作成し、DBに書き込めるかを確認してください。
contentImage022.jpg

本番環境の課金について

ここまでの構築で、herokuの料金は発生しません。無料版の場合、herokuのコンテナにアクセスがないと、自動的にスリープモードに入ってしまうので、スリープ状態でユーザーからのアクセスなどが入ると、レスポンスに時間がかかってしまうリスクがあります。
またnext.js等のCDNを持ったクライアントツールを利用する場合、デプロイのビルド時にタイムアウトしてしまうリスク等が発生します。
そういったリスクを避けたい場合は、課金を行うことをおすすめします。herokuのコンテナの課金は$7/月からです。クラウド型のHeadlessCMSに比べても格安ですので検討してみてはいかがでしょうか。またアクセスがPV1万程度であればS3のストレージ料金も数百円くらいに収まる計算なので、かなり安いランニングコストになります。

終わりに

以上がStrapiの本番環境構築手順の解説でした。 StrapiV4は2021年の12月にリリースされたばかりの新しいツールです。公式でもドキュメントや開発ツールの用意が間に合っていないのが現状です。公式の情報最新情報も合わせて確認しましょう。
picture
hanzochang
代表取締役 半澤勇大
慶應義塾大学卒業後、AOI Pro.にてWebプランナーとして勤務。ナショナルクライアントのキャンペーンサイトの企画・演出を担当。その後開発会社に創業メンバーとして参加。Fintech案件や大手企業のDXプロジェクトに関わり、その後個人事業主として独立。2023年にWeb3に特化した開発会社として法人化。

2017年ごろより匿名アカウントでCryptoの調査等を行い、ブロックチェーンメディアやSNSでビットコイン論文等の図解等を発信。
hanzochangはフリーランスのエンジニアです
スキルセットや特徴は下記よりご確認いただけます
fixed
© 2023 hanzochang