Sinatra on Heroku (LetsEncrypt)

<img src=https://letsencrypt.org/images/le-logo-twitter.png width=200px>

> Let's Encrypt の仕組み - Let's Encrypt 総合ポータル : https://letsencrypt.jp/technology/

## Sinatra アプリつくる

Gemfile

```rb:Gemfile
source "https://rubygems.org"

ruby '2.3.3'
gem 'sinatra'
```

```rb:app.rb
#! /usr/bin/env ruby

require 'bundler'
Bundler.require

class App < Sinatra::Base
  get '/' do
    "Hello World"
  end
end
```

## Heroku に デプロイする

```rb:config.ru
require './app'
run App
```

```
$ git init
$ git add .
$ git commit -m 'first commit'
$ heroku create <アプリ名>
$ git push heroku master
```

heroku open して 確認できる。

## LetsEncrypt を追加する

```rb:Gemfile
gem 'rake'
gem 'platform-api', git: 'https://github.com/jalada/platform-api', branch: 'master'
gem 'letsencrypt-rails-heroku'
```

- `rake` は、証明書発行、更新用の Task を起動するため
- `platform-api` は、Heroku の API を使うため（バージョンアップしたらいらなくなるかも）

のために追加

###  Rakefile 追加

```rb:Rakefile
require 'letsencrypt-rails-heroku'
Letsencrypt.configure
spec = Gem::Specification.find_by_name 'letsencrypt-rails-heroku'
load "#{spec.gem_dir}/lib/tasks/letsencrypt.rake"
```

これで、Heroku 上で Rake の Task を実行できるようになる。

### アプリの方にもミドルウェアを追加する


```rb:app.rb
#! /usr/bin/env ruby
require 'bundler'
Bundler.require

class App < Sinatra::Base
  Letsencrypt.configure
  use Letsencrypt::Middleware
  
  get '/' do
    "Hello World"
  end
end
```

もっかい、Heroku に  デプロイ。

## 証明書の設定

適当なドメインを買っておく。
（今回は、`b-dayz.date` っていうダサいドメインをお名前.com で買った）

```
$ heroku domains:add b-dayz.date
```

※ `.herokuapp.com` のドメインに `CNAME` で設定しておく

### 環境変数に色々設定する

```
$ heroku config:add ACME_DOMAIN=b-dayz.date
$ heroku config:add ACME_EMAIL=<メールアドレス>
$ heroku config:add HEROKU_APP=<Heorkuで作ったアプリ名>
```

```
$ heroku plugins:install heroku-cli-oauth
$ heroku authorizations:create -d "LetsEncrypt"
$ heroku config:add HEROKU_TOKEN=<前のコマンドで表示されたTOKEN>
```

### Heroku のプラン変更

free の dyno では、証明書の登録がサポートされていないので、hobby($7/month)にあげる。

```
$ heroku dyno:type hobby
```

これで準備が整いました。

```
$ heroku run rake letsencrypt:renew
```

`https` で確認できるはず。

![image](https://qiita-image-store.s3.amazonaws.com/0/4598/3a6435c5-5dbb-9d26-1685-ecd0d4378656.png)

## http 対応

http でもリクエストは受け付けているので、https に矯正させる。

```rb:Gemfile
gem 'rack-ssl-enforcer'
```

```rb:app.rb
use Rack::SslEnforcer if production?
```

## `.herokuapp` ドメイン対応

`.herokuapp` のドメインの方でもリクエストを受けているので、301 かけておく。

```rb:app.rb
class App < Sinatra::Base
  before do  
    ensure_domain if production?
  end

  # def hoge end
  # def fuga end

  private

  def production?
    ENV['RACK_ENV'] == 'production'
  end

  def ensure_domain
    return unless /\.herokuapp.com/ =~ request.env['HTTP_HOST']
    redirect "https://#{ENV['FQDN']}#{request.env['REQUEST_PATH']}", 301
  end
end
```

```
$ heroku config:add FQDN=b-dayz.date
```

## 証明書の自動更新

> https://elements.heroku.com/addons/scheduler

```
$ heroku addons:create scheduler:standard
$ heroku addons:open scheduler
```

![image](https://qiita-image-store.s3.amazonaws.com/0/4598/bde3971d-5731-3339-45bc-699e5ad66db5.png)

Job　を追加して完了

```bash
if [ "$(date +%d)" = 01 ]; then rake letsencrypt:renew; fi
```

## REF

- pixielabs/letsencrypt-rails-heroku: Automatic LetsEncrypt SSL certificates in your Rails app on Heroku : https://github.com/pixielabs/letsencrypt-rails-heroku

## 追記

https://blog.heroku.com/announcing-automated-certificate-management

https://devcenter.heroku.com/articles/understanding-ssl-on-heroku

<blockquote class="twitter-tweet" data-lang="ja"><p lang="en" dir="ltr">Free and automated <a href="https://twitter.com/hashtag/SSL?src=hash">#SSL</a> certs for all paid Heroku dynos are now generally available, issued by <a href="https://twitter.com/letsencrypt">@letsencrypt</a>: <a href="https://t.co/WhMrrH8ZkV">https://t.co/WhMrrH8ZkV</a> <a href="https://t.co/yYLJ48cWXb">pic.twitter.com/yYLJ48cWXb</a></p>&mdash; Heroku (@heroku) <a href="https://twitter.com/heroku/status/844213289097859072">2017年3月21日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>