社WebをAWS s3 + cloudfrontなサーバーレス環境に移行した話

# 背景

社Webを今まではレンタルサーバでHostしていたのですが、フォーム以外は極めてStaticな内容なので今流行りのサーバーレスな環境に移行してナレッジを貯め込みながらもコスト削減したいというところです。なお、すでに過去の偉人たちが残してくださっているドキュメントが多数ございますので、本記事では具体的にハマりそうなポイントを中心に書いていきたいと思います。

# Before

自分が契約しているさくらインターネットさんに置いていました。フォーム部は[phpで社内のSlackに飛ばす](http://qiita.com/tokifuji/items/f7ef227df364f340bc67)というものになっておりました。

# After

大枠で下記な感じで対応しました。[^1]

[^1]: DNSはRoute53を向いているという前提で…

1. Hostはs3
2. SSL証明書はAmazon Certificate Manager && cloudfront
3. フォームは[Stacktodo](https://stacktodo.com)で相変わらずSlackに飛ばす
4. Route53からCNAMEをcloudfrontに向ける

# s3で静的コンテンツをHostする

もう説明は不要だと思います。この辺りなどを…
[独自ドメインを使ってAmazon S3で静的Webサイトをホストする - Qiita](http://qiita.com/Ichiro_Tsuji/items/c174d580587a622d3358)

# Amazon Certificate Manager via cloudfrontでSSL設定

SSLを設定する場合はどうしてもcloudfrontが必要になります。Amazon Certificate Managerを利用してSSL証明書を発行する必要があるのですが、cloudfrontで発行する証明書はUSなRegionで発行されている必要があるためcloudfrontのCreate Distributionから発行手続きを行ってください。ということでここが小さなハマりポイントになります。
![image](https://qiita-image-store.s3.amazonaws.com/0/38292/eef71b37-b093-ad19-e2fb-2927429a8ae5.png)


Amazon Certificate Managerからドメイン確認のメールが飛んできますのでURLを踏んでAcceptしましょう。詳しい手順は以下を読むと良いでしょう。
[S3+CloudFront+ACM(AWS Certificate Manager)でHTTPS静的サイトを作ってみた - Qiita](http://qiita.com/toshihirock/items/914f408cd565b66fe9f9)

ビルドにしばらくかかりますのでChromeの恐竜と戯れるなどして待ちましょう（謎）
https://youtu.be/UtcGgJxVkfU

# Stacktodoでフォームを作る

以前はSlackのIncoming Webhookを使ってphpでSlackに投稿していました。Lambda + API Gatewayを使うという方法もありますが、今回はこういったサービスを使ってみることにしました。（たぶん、飽きたらLambda + API Gatewayに移行するかもですが…）
[Stacktodo | Superbot for Slack](https://stacktodo.com)

一応、`日本語でおｋ`という人のために説明しておきますと、Stacktodoとは…という説明は今回割愛しますが、物凄くお手軽にSlack BotをIntegrateしてくれるサービスみたいです。そのいくつかある機能の中のフォームを今回使いました。
https://stacktodo.com/tools/form

## StacktodoでBotをセットアップする

英語ですがわかりやすいチュートリアルがあります。是非ご覧ください。
https://stacktodo.com/bot

### Stacktodo BotをSlackに招待する

https://youtu.be/IC_pyIjTrgI

### Slack ChannelにStacktodoを招待する

Slack Channelを作成 or 既存のSlack ChannelにStacktodoを招待して`@stacktodo form here`で新しいフォームが作成されます。
https://youtu.be/xFFI8ZAw5f4

フォームタイトルやフィールド定義などをしたら`@stacktodo form code`とするとEmbedするHTMLが出力されます。
https://youtu.be/iRrCgoOahtI

フォームの設定方法などのドキュメントは下記をご確認ください。
[How to use the Form tool | Slack](https://slack-files.com/T096T9C4S-F0D03K62K-91301e85f9)

### `@stacktodo form code`で出力したコードをHTMLにマージする

既存HTMLに自分が用意したCSSなどであたっている要素名（Classやidなど）といい感じにマージしてください。下記の例ですとformのidが`s2do-form`となっているので合わせたりしました。簡単なValidationなどもついでにやっておくとなお良いでしょう。

```html
<form id="s2do-form" action="#" method="POST">
<div class="form-group">
<label>name</label>
<input type="text" name="name">
</div>
<div class="form-group">
<label>email</label>
<input type="text" name="email">
</div>
<div class="form-group">
<label>message</label>
<input type="text" name="message">
</div>
<button type="submit">Submit</button>
</form>
<script type="text/javascript" src="https://s3.amazonaws.com/stacktodoapi/0_0_4/stacktodo_full.min.js"></script>
<script type="text/javascript">new window.stacktodo.ui.SlackForm(document.getElementById('s2do-form'), { form: '********-****-****-****-************' });</script>
```

### Stacktodoの謎

Pricingのページが見つからないのですが…誰かご存知ならぜひ…でも、たぶんまだ無料で使えるっぽいです。
https://stacktodo.com

# s3へアップロード

結構手順を端折っていますが、実際には一応今の状態でGithubのリポジトリにpushくらいはしています。あとは`aws configure`済の環境で`clone`して`aws s3 cp --recursive`とかしてs3にアップロードしました。

## s3上のsvgファイルのヘッダー情報がおかしい問題勃発

Hamburger Menuなどで一部svgファイルを使っているのですがどうもヘッダー情報がおかしい。mime content-typeに`binary/octet-stream`と表示されている。どうやっても`image/svg+xml`にならない。

### s3にcpするときに`--content-type image/svg+xml`を付ける

こんな感じである。

```
aws s3 cp --content-type image/svg+xml img/common/icon_fb.svg s3://{destination-s3-bucket}/img/common/
```

Header情報を確認するとこんな感じになっていればOK

```sh
-bash-4.2$ aws s3api head-object --bucket {destination-s3-bucket} --key img/common/icon_fb.svg
{
    "AcceptRanges": "bytes", 
    "ContentType": "image/svg+xml", # ←ココ！！！ 
    "LastModified": "Mon, 13 Feb 2017 13:26:30 GMT", 
    "ContentLength": 1092, 
    "ETag": "\"********************************\"", 
    "Metadata": {}
}
```

### CSSのbackground-image url()をcloudfrontに向ける

これを以下の様に直す。

```diff:common.css
.btn--facebook {
-    background-image: url(../../img/common/icon_fb.svg);
+    background-image: url(https://{your-cloudfront-url}/img/common/icon_fb.svg);
}
```

### s3上のsvgファイルを公開する

Chrome Developers Consoleを見ると`403 forbidden`になったりしていた。なのでs3で対象のsvgファイルを公開にすることで解決できた。
![image](https://qiita-image-store.s3.amazonaws.com/0/38292/4a704b0c-7c1b-3096-fcf0-3090a0a85641.png)

svgファイルが表示されたぞ！！やった！！！！
![image](https://qiita-image-store.s3.amazonaws.com/0/38292/cd5ddb2f-90a7-78b5-8e75-85309f43f6fc.png)


### naked domainの対応

sslなしでnaked domainにアクセスするとこんなん(Bad Request The request could not be satisfied.)出てますよっていうご指摘をいただきました。
![image](https://qiita-image-store.s3.amazonaws.com/0/38292/002e18a0-671e-8c5e-9e6e-7078f16b9447.png)

おっといけねぇということで別途naked domain用にs3 bucketを作ってStatic website hostingの部分でリダイレクト設定を以下のように行いました。
![image](https://qiita-image-store.s3.amazonaws.com/0/38292/fbeeda90-d844-e97a-1898-fd1689847296.png)

後はRoute53のnaked domainのAレコードをこのs3 bucketに向ければOKです。お騒がせしました:bow:

# ということでお疲れさまでした。

これで無事にリリースできました。これであなたも快適なs3 + cloudfront + Stacktodoライフ（だからなに）をおくれますね:eyes:
https://www.elevennines.co.jp