Middleman で構築したウェブサイトを Amazon S3 に展開する


Middleman は、静的なウェブサイトを構築するためのツールで、特に Rails を使っている人なんかは、取っかかり易いツールとなっている。

http://middlemanapp.com/

せっかく構築を楽チンにしているので、アップロードも楽チンにしたい！ということで、コマンド一発でアップロードできるような環境を作ってみる。Middleman には、Extension があって、既にこういった問題を解決するための機能が揃っている。今回は、アップロード先に Amazon S3(以降 S3) を選択してみた。S3 には、静的なウェブサイトをホスティングするための機能が備わっている。

http://docs.aws.amazon.com/AmazonS3/latest/dev/WebsiteHosting.html

Extension として S3 にアップロードするためのものは、現時点で 2つある。

* middleman-sync
* middleman-s3_sync

前者は、Rackspace などにも対応していて、後者は S3 Only である。

## middleman-sync を試す

とりあえず、middleman-sync から試してみる。導入は非常に簡単である。Gemfile に追加して、

```Gemfile
gem "middleman-sync", "~> 3.0.12"
```

bundle install して終了である。ちなみに、現時点での最新版である 3.0.12 導入時点では、実行すると fog の Warning が表示される。これを回避するためには、以下の Gem を追加しておくといい。

```Gemfile
gem “unf”
```

続いて、config.rb への設定の追加である。

```ruby:config.rb
# Activate sync extension
activate :sync do |sync|
  sync.fog_provider = 'AWS' # Your storage provider
  sync.fog_directory = ‘www.example.com’ # Your bucket name
  sync.fog_region = ‘ap-northeast-1’ # The region your storage bucket is in (eg us-east-1, us-west-1, eu-west-1, ap-southeast-1 )
  sync.aws_access_key_id = 'super' # Your Amazon S3 access key
  sync.aws_secret_access_key = 'secret' # Your Amazon S3 access secret
  sync.existing_remote_files = 'keep' # What to do with your existing remote files? ( keep or delete )
  # sync.gzip_compression = false # Automatically replace files with their equivalent gzip compressed version
  sync.after_build = false # Disable sync to run after Middleman build ( defaults to true )
end
```

設定における注意ポイントは、最後の after_build の設定である。これが true だと build したあとに自動的に sync まで行われてしまう。build と sync のタイミングを分けたい場合は、必ず false に設定しておくこと。

ちなみに、上記のような設定で sync を実行するとエラーになる。現時点では、Bucket 名に “.” が含まれている場合に、うまく動作しないようである。

https://github.com/karlfreeman/middleman-sync/issues/30

なぜ、”.” が含まれている Bucket 名にしたいのかというと、S3 上に展開したウェブサイトを、S3 側で準備しているエンドポイントを使用せず、任意の URL でアクセスできるようにする場合、そのドメイン名で Bucket を作る必要があるため、である。

## middleman-s3_sync を試す

現状の middleman-sync では、うまくいかないので、middleman-s3_sync に期待してみる。こちらも導入は簡単である。

```Gemfile
gem 'middleman-s3_sync'
```

こちらは、unf の件も解決済みのようである。なにか期待できそうな感じがする :)

続けて、config.rb へ設定を追加する。

```ruby:config.rb
activate :s3_sync do |s3_sync|
  s3_sync.bucket                     = ‘www.example.com' # The name of the S3 bucket you are targetting. This is globally unique.
  s3_sync.region                     = ‘ap-northeast-1’     # The AWS region for your bucket.
  s3_sync.aws_access_key_id          = 'AWS KEY ID'
  s3_sync.aws_secret_access_key      = 'AWS SECRET KEY'
  s3_sync.delete                     = false # We delete stray files by default.
  s3_sync.after_build                = false # We do not chain after the build step by default. 
  s3_sync.prefer_gzip                = true
  s3_sync.path_style                 = true
  s3_sync.reduced_redundancy_storage = false
  s3_sync.acl                        = 'public-read'
  s3_sync.encryption                 = false
end
```

Github 上のサンプルを見ても明らかだが、”.” 付の Bucket 名でサンプルが作られており対応済みであることがわかる。この件で重要な設定は path_style の部分で、これを true にすることで、問題を解決することができる。こちらも after_build の設定があるので、注意しておく必要がある。

s3_sync を実行すると、何事もなく完了。現時点では、middleman-s3_sync を使ったほうがよさそうだ。

## ふとした疑問

ところで、そもそもなんで似たような Extension を作ったんだろう？ その答えは GitHub に書いてあった。

> The only issue I have with it is that it pushes every files under build to S3 and doesn't seem to properly delete files that are no longer needed.

というわけで、s3_sync のほうが挙動として賢そうなので、ここでとりあげた問題が解決したとしても、s3_sync のほうがおすすめと言えそうである。