仕事で聞く要望のうちいくつかは CMS 使うほうが今後のメンテが楽そうだなと感じる機会がよくある。Hugo でサイトを構築するとして、動かすのはなるべく楽に面倒見ずにすませたい。でも独自ドメインだったりある程度機能は求めたい。というわがままを Netlify なら叶えてくれるんじゃないかということで Netlify を試している。 その中で、本番はいいんだけど動作確認用の環境をどうしようかなーというので迷って Deploy previews で対応したことの記録。結論には Business plan で有効になる site access control by roles が必要なので仕事とはいえお金は Pro までしかかけられないという場合は使えないけど、そういうときはトレードオフで URL がばれなきゃいいっしょの精神でいけばいいと思う。

なお、同じ会社で Netlifyが仕事で使えるか試す(追記あり) という方法でやっている話へのアンサーソングでもある。

やりたいこと

まずやりたいことから。

  • Netlify で動作確認をする環境は public に見える状態を避けたい
  • Netlify を使う動機がリポジトリをつくったらあとはなるべく環境構築やその後のデプロイの手間をかけたくないというものなので手間かけたくない
  • 本番となるべく近い形で動作の確認をしたい

考えてたこと

同じ会社で同僚が似たことをやっていたのでまずはその repo を見たり、軽く話を聞いたりしてたんだけど、好みからいくと本人も書いているとおり “しかし、Productionはデプロイの方法を別で作っておかないといけないという面倒なことになってしまう。つらいね。” についてはだいぶ後で嫌になりそうで回避したいなと感じたのと、Heroku で Review Apps の便利さを享受したことのある身としてはぜひ Deploy previews を活かしてやりたい。そして、環境に応じたあれこれをビルド時に考慮してやれば稼働環境は同一でいけそうな気がするので Selective Password Protection のやり方は筋がよさそうに感じる (というか Basic 認証ならこれでいい)。

ということで、 IdentityVisitor Access Control を使ってやってみた。

やってみたこと

Makefile じゃなくて rake でやりたいなーとごちゃごちゃやった結果、 Makefile で書くのが一番シンプルだったというサンプル があるのでこのコードを見ながらやってみたことを解説。

環境ごとにビルドを変える (production/deploy-preview)

環境ごとのビルドについては Selective Password Protection に倣って netlify.toml で制御した (repo では rake でやってるが困るまで make でいいと思う)。

[context.production]
  command = "make production"

[context.deploy-preview]
  command = "make deploy_preview"

権限 (Role) がなければ拒否する

このあとビルドの中でいくつかファイルを生成するので元ファイルを netlify ディレクトリに置いておく。

Visitor Access Control で redirect を使って Role に指定の権限がなければ拒否するやり方が書かれているのでそのとおりに _redirects ファイルを書いてみる。

/*   200!      Role=user
/*   /login    401!

user role を持っていれば / 以下にアクセス可能。そうでなければ 401 Unauthorized/login へ飛ばしている。

ログイン

ログインは Netlify Identity Widget で用意してみた。といっても、README に書いているとおりのサンプルコードをつっこんだ login.html を用意しただけだ (repo に置いてるのは少しコメント消したりしたけど基本はほぼサンプルのとおり)。

<!DOCTYPE html>
<html>
<head>
  <title>A static website</title>

  <!-- include the widget -->
  <script type="text/javascript" src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script>
</head>
<body>
  <!-- Add a menu:
   Log in / Sign up - when the user is not logged in
   Username / Log out - when the user is logged in
  -->
  <div data-netlify-identity-menu></div>

  <!-- Add a simpler button:
    Simple button that will open the modal.
  -->
  <div data-netlify-identity-button>Login with Netlify Identity</div>
</body>
</html>

ビルド

最後にここまで準備したものを使ってビルドをするのがこの Makefile だ。

production:
	hugo

deploy_preview:
	hugo && cp netlify/{_redirects,login.html} public/.

deploy_preview 指定で起動されたときは hugo コマンドで実行した public 上の成果物と、アクセス拒否やログインへのリダイレクトを含んだファイルを public へとコピーしているというだけ。どちらが呼ばれるかというのは netlify.toml のところで書いていたとおり、Netlify が環境に応じたほうを呼び出してくれる。

あとは対象のサイトの Identity の設定 (Invite したり Roles を設定したり) や Settings にある Access Control の Set JWT secret から設定をすることで、ログインしないと見られない Deploy previews が実現できる。

冒頭に書いたとおり Business plan が必要になるのが少し金銭面のハードルが上がるのと、Invite users が Identity Free だと 5 人上限でそれを増やしたいときは Identity Pro がさらに必要になるけれど、ぼくにとっては運用しやすそうなバランスに落ち着いた。この辺が気になるなら Basic 認証にしたり、認可自体をあきらめてしまえばいいと思う。

思ったこと

Netlify のサイトをカスタマイズするのにそれぞれのファイルですごいがんばるよりはビルドを分けられるという機能を使うとよさそうだなということ。環境ごとに環境変数が共通になるので環境変数で分岐を実現するということができないから、環境ごとの分岐はビルドをわけてしまって、それぞれが必要なファイルを用意していやるというほうへ倒すとすっきりとできそう。netlify.toml を見ると context specific environment variables の定義があるからファイルを共通にして環境変数によって出し分けするようなこともできそうだけど、だいたいテンプレートがきつくなるパターンな気がする。なので、 context による分岐の実現は道具に加えておくと便利そう。複雑になっても rake 呼び出しにして ERB 使ってよりよいテンプレート管理なんてことも容易にできるし。