これまでバックエンドなしでReact使ったサイトを作ってきたけど,他の人も更新しやすいようにCMSを使った方がいいと思い実装してみた。
条件としては,半分趣味だし多分収益化しないだろうし全て無料であること。
StrapiというHeadless CMSを使いAPIをローカルで構築し,Herokuの無料アカウントにあげた上でフロントエンドからREST APIを使えるようになるまでを書いてみようと思う。
まずCMSとStrapiについて書きますが,既にある程度知っていましたらこちらまで飛ばしてください。そこから先は手順に沿って進めていきます。
目次
そもそもCMSって?
なんでSrapi?
参考にしたページ
ローカルでStrapi Appを作成する
Herokuにデプロイ
問題点とその解決法
まとめ
そもそもCMSって?
content management systemの略。代表的なモノで言うとWordPress。代表的というか,CMSシェア全体の63%を有しているからもはや代表。
WordPressには優れた点も欠点もあるけど,今回使うStrapiとの大きな違いはHeadlessであるか否か。WordPressはフロントエンドの仕組みも含んでおり,さらに大量のプラグインやテーマも使える巨大なシステムとなっている。それに対してStrapiはバックエンドのデータ管理のみを行い,フロントエンドは使う人に任せている。
Strapiと組み合わせやすいように様々なプラグインは用意されているけど,基本的にはフロントエンドがどんなでもREST APIやGraphQLでデータを取得できる。だから一度作ってしまえば,やりたければアプリやIoTデバイスへの拡張も簡単にできるそう。今回はそこまでやらないが,「必要だったらできる!」というのは今後の拡張考えると安心。
なんでSrapi?
まず無料。
Strapi によると,その長所はオープンソースであること,カスタマイズしやすいことなどなど。これらの点も含めて,個人的な魅力はめちゃくちゃ使いやすいこと。
ある程度コーディングに慣れていた方がカスタマイズはしやすいが,最低限必要なことはコマンドラインでnpx create-strapi-app
と叩くだけ。あとは自動でサーバーが立ち上がり,そこに情報を入力していくだけOK。
また公式サイトのチュートリアルとドキュメントはすごく丁寧でよくあるシチュエーションをカバーしてるから,手順に従うだけで必要なカスタマイズは全てできた。なんならStrapi以外の要素も含んだチュートリアルもあるから,完全初心者から作りたいサイト公開までいけそう。
懸念点としては,結構新しいサービスだからネット上の情報は他のCMSに比べるとまだまだ少ない。特に公式は日本語へ対応していないため英語全く知らないと厳しいかも。でも,すごいことにStarpiそのものはある程度日本語に対応していて,アカウント作成やデータの追加をするときに英語で困ることはなさそう。そして日本での普及も進んでいるようで,Strapiとググれば公開一年以内の日本語の記事は一杯出てくる。
日本語で困ったことがあればこちらの記事も参考になるように書きますので,質問・要望あればお願いします!
参考にしたページ
今回は序盤のインストールはStrapiの公式ドキュメントを,その後のHerokuの使い方や問題点の解決法はPascal Couturierさんのブログを参考にさせていただいた。大まかな流れもこれらに準拠する。
Strapi 公式
Strapi Introduction
Pascal Couturierさんのブログ
Self Hosted Free Open Source CMS with Strapi.io
ローカルでStrapi Appを作成する
nodeのインストール
まずnodeをこちらからインストールして,npm
とnpx
がコマンドラインから使えるようにする。
現在の私のnodeなどのバージョンはこちら。
$ node --version
v12.16.1
$ npm --version
6.14.8
Strapi appを作る
コマンドから以下を叩くと,./starpi-app
に初期化されたStrapiのアプリができる。
$ npx create-strapi-app starpi-app --quickstart
strapi-app
のところは任意のApp名。アプリを作ると同時にhttp://localhost:1337
にサーバーが立ち上がる。作成完了まで時間かかるが,以下の内容が表示されたら完了の合図。
To manage your project 🚀, go to the administration panel at:
http://localhost:1337/admin
To access the server ⚡️, go to:
http://localhost:1337
http://localhost:1337/admin
にアクセスしてみよう。
ちなみに,間違えてサーバーを閉じてしまった場合は
$ cd ./starpi-app
$ npm run develop
で再開できる。
Strapi管理画面を表示
http://localhost:1337/admin
にアクセスすると,初回は次のように自分の情報の入力画面が表示される。
情報を入力したら以下の管理画面表示される。
-
コレクションタイプ
データベースの各テーブルにあたるメニュー。データベースのテーブルをstrapiでは「コンテンツ」,コラムを「フィールド」と呼ぶ。新しくコンテンツなどを作るとここに表示され,データを追加したり編集したりできる。
-
Content-Types Builder
新しいコンテンツなどを作成する場所。ローカルの開発環境では使えるが,Herokuなどにあげるプロダクション版では新しいコンテンツの作成はできなくなるので,まず必要なコンテンツをローカルで作ってからHerokuにあげる。
-
設定
各種設置を行うメニュー。今回は「ロールと権限」の設定を行うが,他にメディアライブラリやメールテンプレートの設定などができる。
新しいコンテンツの作成
Content-Types Builderから公式のチュートリアルと同じようにrestaurantコンテンツを作成してみる。これは後ほど削除できるが,難しくないのでまず自分の必要そうなコンテンツをこれをもとに作成してみてください。
-
「+ Create new collection type」をクリック
-
restaurant と入力し「続ける」を押す
-
「Text」フィールドを選択
-
Nameに name と入力
-
「高度な設定」を選択し,「必須フィールド」と「一意のフィールド」を選択する
-
下にスクロールし「+ Add another Field」をクリックし,「Rich Text」フィールドを選択
-
Nameに description と入力し「終了」をクリック
-
右上の保存ボタンを押し,サーバーがリスタートされるのを待つ。表示が再開されない場合はページを再読み込みするか,コマンドラインの表示を確認する。
成功すると,左のコレクションタイプに「・Restaurants」が追加されているはず。
試しにいくつかデータを追加してみましょう。
-
右上から「+restaurantを追加」をクリック
-
好きなレストラン名をNameに,その説明をDescriptionに書き右上から保存,そしてPublishする。(Publishしないと,表示はされるが外部からは基本表示されない状態になる)
テストのために同様の手順でいくつか作っておきましょう。
APIの公開設定
デフォルトではAPIをリクエストすると拒否されるので,どこまで許可するかを設定する。
-
左から「設定」>「ロールと権限」を選択すると,存在するロールの種類が表示される。デフォルトではログインしたメンバーが使えるAuthenticatedと誰でも使えるPublicの二つある。
-
Publicを選択し,「権限」から許可するAPIをチェックする。デフォルトでは全てオフになっているため,まずrestaurant数を表示する
count
,全データ表示するfind
とidを指定したものを表示するfindone
を許可して右上の「Save」ボタンをクリックする。
APIを試してみる
手早くAPIを試すには,http://localhost:1337/restaurants
(restaurantを自分の設定したコンテンツ名に変える。)にアクセスしてみよう。
権限設定がきちんとできていれば,上のようにrestaurantsのデータがjson形式で帰ってくる。もし
{"statusCode":403,"error":"Forbidden","message":"Forbidden"}
が帰ってきたら,権限がうまく設定できていない。もう一度設定を見直してみましょう。
詳しいAPIの送信・受け取り方法はフロントエンドの実装によるので説明しないが,Strapiではデフォルトで以下の6種類が使える。例えばrestaurantコンテンツの場合は{content-type}
にrestaurants
を当てはめて送ってみよう。現在の設定ではcount
,find
とfindone
のみ許可してあるので,他のAPIを送ると拒否される。Publicに許可するのは危ないので,必要だったら先ほどの設定においてAuthenticatedを選択し許可したいアクションを設定しましょう。
アクション名 | メソッド | パス | 説明 |
---|---|---|---|
find | GET | /{content-type} | {content-type}の全要素を取得 |
findone | GET | /{content-type}/:id | {content-type}の:id番目の要素を取得 |
count | GET | /{content-type}/count | {content-type}の要素数を取得 |
create | POST | /{content-type} | {content-type}の新要素を作成 |
delate | DELETE | /{content-type}/:id | {content-type}の:id番目の要素を削除 |
update | PUT | /{content-type}/:id | {content-type}の:id番目の要素を更新 |
ちなみに,Postmanというアプリが使いやすくAPIのテストに役立つのでお勧めです。もちろん無料。
Download Postman | Try Postman for Free
Herokuにデプロイ
Herokuでは少なくとも1サーバーは無料で使える。機能はもちろん限られるが,十分すぎるぐらい高機能な上,他の無料サービスを組み合わせれば足りない点もある程度補える。
Herokuに作ったStrapi Appをあげてみよう。細かい設定は公式の以下のドキュメントを参考にし,データベースはPostgreSQLを用いた。
gitがない場合は,あらかじめインストールしておこう。
注意
コンテンツの各要素はデータベースに入っているため反映されません。必要だったら新しく作り直すか,後ほどlocalのデータをAPI使ってHerokuで再作成しましょう。または外部のデータベースを使えばローカルとプロダクションで同じデータを使えます。
デプロイ先では新しいコンテンツの作成ができなくなります。必要だったらHerokuにあげる前に他のコンテンツを作っておきましょう。
Heroku CLIダウンロード
まずHeroku CLI
をそれぞれのOSに合わせてダウンロードする。
Mac :
https://cli-assets.heroku.com/heroku.pkg またはHomebrewを使って
$ brew tap heroku/brew && brew install heroku
Windows :
64-bit https://cli-assets.heroku.com/heroku-x64.exe
32-bit https://cli-assets.heroku.com/heroku-x86.exe
Ubuntu :
$ sudo snap install --classic heroku
Herokuにログイン
コマンドで
$ cd ./strapi-app #strapi app内に移動しておく
$ heroku login
と打つとログインフォームが立ち上がる。アカウントがない場合はこちらから作ることもできる。
この画面が表示されたらコマンドに戻る。
.gitignoreファイルを更新
.gitignore
ファイルに以下の一行を追加する。
package-lock.json
Herokuではyarnを使っている影響でpackage-lock.json
を追加するとエラーが出るらしい。
ドキュメントにはないが,yarn
を以下で起動しyarn.lock
を更新しておく方がいいかも。(自分の場合はこれをしなかったときエラーを出したため)
$ yarn install
gitをinitする
gitを作りコミットする。
$ git init
$ git add .
$ git commit -m "Initial Commit"
Herokuに新プロジェクトを作成
$ heroku create strapi-app
strapi-app
には好きなプロジェクト名を当てはめる。何も入力しなければ自動で適当な名前が付けられる。
Herokuにデータベースを作成
PostgreSQLのデータベースを作成する。
-
コマンドからHerokuのPostgresアドオンをいれる
$ heroku addons:create heroku-postgresql:hobby-dev
-
データベースの情報を確認
$ heroku config
DATABASE_URL: postgres://ebitxebvixeeqd:dc59b16dedb3a1eef84d4999sb4baf@ec2-50-37-231-192.compute-2.amazonaws.com: 5432/d516fp1u21ph7b
のような内容が表示されればデータベースの立ち上げは完了。 -
必要なPostgresパッケージを追加
$ yarn add pg pg-connection-string
または
$ npm install pg pg-connection-string --save
-
データベース設定ファイルを作成
config
フォルダに新しいディレクトリenv/production
を作り,以下の内容でdatabase.js
をそこに追加する。const parse = require('pg-connection-string').parse; const config = parse(process.env.DATABASE_URL); module.exports = ({ env }) => ({ defaultConnection: 'default', connections: { default: { connector: 'bookshelf', settings: { client: 'postgres', host: config.host, port: config.port, database: config.database, username: config.user, password: config.password, }, options: { ssl: false, }, }, }, });
変更をコミットし,Herokuにデプロイする
$ git add .
$ git commit -m "Update database config"
$ git push heroku master
これでHerokuにデプロイが開始する。結構時間がかかるが,うまくいくと以下のような内容が表示される。
remote: -----> Launching...
remote: Released v6
remote: https://strapi-app.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/strapi-app.git
45a0a5a..e43g2ef master -> master
上記のhttps://strapi-app.herokuapp.com
該当部分にアクセスした時に以下の画面が表示されたら完了!
できない場合は,Herokuのログを以下を使い確認してみてください。
$ heroku logs --tail
デプロイ版の管理画面を表示
http://strapi-app.herokuapp.com/admin
(strapi-app
を自分のアプリ名に変更)にアクセスすると,再度ユーザー登録が求められる。
データベースに保存されたコンテンツの各要素と設定は反映されない。まずログインしたら「ロールと権限」を設定してからAPIを使って再度追加したりしよう。
問題点とその解決法
以上でHerokuにStrapiを使ったアプリの立ち上げは終わった。ただ,このままではいくつかの点で実際に運用するには問題がある。
HTTPSに対応できない
Herokuは有料サーバーなら無料でSSLが使え,HTTPS接続に対応できるようになる。逆にいうと,どんなに頑張っても完全無料でHTTPS接続することは不可能らしい。
APIのテストをするだけなら問題ないと思っていたためこの点は最初は気にしていなかったが,どうもフロントエンド側からAPIを叩くときにhttpsじゃないと勝手にブロックされるらしい。安心。
どう解決するかというと,Cloudflareというサービスを使う。
これは簡単にいうと,Herokuとフロントエンドの間に入り,ブラウザとサーバーとの通信をセキュアにするサービスである。他にもいろいろ設定できるが,今回はSSL/TLS設定を目的に使用する。
細かい設定方法は英語になるがこちら。
概要としては,
-
ドメインを取得する
お名前.comを用いるのが楽ではあるが,無料のドメインも探せばある。http://www.freenom.comとかなら少なくとも1年間無料でドメインを取得できる。
例として,
example.com
というドメインを取得したとして以下進める。 -
Herokuにドメインを追加
$ heroku domains:add example.com
追加が完了したら,後ほど使うDNS Target(以下の
whispering-willow-5678.herokudns.com
該当部)を取得しておく。$ heroku domains === strapi-app Heroku Domain strapi-app.herokuapp.com === strapi-app Custom Domains Domain Name DNS Record Type DNS Target example.com ALIAS or ANAME whispering-willow-5678.herokudns.com
-
Cloudflareに登録し,取得したドメインを追加する
Cloudflareの登録はこちらから
登録する過程でドメインの追加といくつか設定を行う。この時点で4.の設定を行ってもいい。
nameserversの設定はドメインを取得したサイトごとに異なる。freenom.comならhttps://my.freenom.com/clientarea.php?action=domainsから該当するドメインについて以下のように選択していくと設定画面に行ける。
「Manage Domain」>「Management Tools」>「Nameservers」
-
CloudflareのDNSを以下のように設定する
TypeはCNAMEを選択,Nameはサブドメインがない(wwwとかついていない場合を設定する)ときは@,そしてIPv4 addressに2.で取得したDNS Targetを設定しセーブする。
-
しばらく(最大で1日)待つとCloudflareから使えるようになったとの連絡がメールで届くはず。
設定が完了するとhttp://strapi-app.herokuapp.com
の代わりにhttps://example.com
からstrapi appにHTTPSで接続できるようになる。
もちろんですが,これでセキュリティが万全になるといったものではないです。さらに追加の設定も可能なので,公式のドキュメントの確認をお願い致します。
https://help.heroku.com/GVS2BTB5/why-am-i-getting-error-525-ssl-handshake-failed-with-cloudflare-when-using-a-herokudns-com-endpoint
写真を保存できない
Strapiにはメディアライブラリという写真などのファイルを管理する機能がある。だが,Herokuの無料サーバーはエフェメラルファイルシステムといってリスタートされるたびにストレージが消えるという特性があるため,メディアライブラリに保存されたものはサーバーがスリープするたびに消えてしまう。
その対応として,外部のメディア管理サービスにつなげる。今回はCloudinaryを使ってみた。
公式だとAWSのS3を使っているが,手順としては同じである。
-
Providerをインストールする
$ yarn add strapi-provider-upload-cloudinary
または
$ npm install strapi-provider-upload-cloudinary --save
-
Cloudinaryに登録しアカウント情報を取得する。
Cloudinaryへの登録はこちら。
登録完了すると以下のDashboardが表示される。
こちらからCloud name,API KeyとAPI Secretの三つを後ほど使う。
-
Scrapi App内に
.env
ファイルを作成し,先ほど取得した情報を設定する。CLOUDINARY_NAME="Cloud name" CLOUDINARY_KEY="API Key" CLOUDINARY_SECRET="API Secret"
それぞれ2.で取得した値を入力し保存し,
config
内にplugins.js
を以下の内容で作成する。module.exports = ({ env }) => ({ upload: { provider: 'cloudinary', providerOptions: { cloud_name: env('CLOUDINARY_NAME'), api_key: env('CLOUDINARY_KEY'), api_secret: env('CLOUDINARY_SECRET'), }, }, });
もしCloudinaryをHerokuのみで用いてローカルでは使わない場合は,これらの情報をHerokuに直接登録することもできる。
$ heroku config:set CLOUDINARY_NAME="Cloud name"\ CLOUDINARY_KEY="API Key"\ CLOUDINARY_SECRET="API Secret"
その上で,先ほど設定した
config/plugins.js
をconfig/env/production/
に移動する。.env
ファイルは削除しておく。 -
Herokuを更新する。
$ yarn install $ git add . $ git commit -m "Update upload plugins" $ git push heroku master
完了!
管理画面の「メディアライブラリ」から写真をアップロードすると,Cloudinaryにアップロードされる。ストレージと通信量には制限があるが,無料プランでもしばらくは大丈夫そう。
まとめ
バックエンドでAPI作って使うのは,まずサーバーがお金かかるしバックエンドって難しいしで諦めていた。その分フロントエンド側を工夫して似たようなことをできないか試してきた。
今回Strapiを使って作ってみたがめちゃくちゃ使いやすいので,他の用途にもいろいろ試してみようと思う。またメインのプロダクトはReactで作っているので,GatsbyといったStrapiとの相性がいいサービスも使ってみたい。
セキュリティの点などはまだまだ中途半端な気がするので,アドバイスあればお願いします!無料の範囲内でどこまでできるか試していきたいです。