Sinatra on Heroku (LetsEncrypt)


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

Sinatra アプリつくる

Gemfile

Gemfile
source "https://rubygems.org"

ruby '2.3.3'
gem 'sinatra'
app.rb
#! /usr/bin/env ruby

require 'bundler'
Bundler.require

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

Heroku に デプロイする

config.ru
require './app'
run App
$ git init
$ git add .
$ git commit -m 'first commit'
$ heroku create <アプリ名>
$ git push heroku master

heroku open して 確認できる。

LetsEncrypt を追加する

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 追加

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 を実行できるようになる。

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

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 で確認できるはず。

http 対応

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

Gemfile
gem 'rack-ssl-enforcer'
app.rb
use Rack::SslEnforcer if production?

.herokuapp ドメイン対応

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

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

Job を追加して完了

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

REF

追記