Heroku で Let's Encrypt を使って SSL 対応する
Heroku で動かしている Rails アプリを SSL 対応した。SSL 証明書は Let’s Encrypt で取得したので無料。 ただし、Heroku で SSL を使うためには、Paid Dyno が必要なので、月 7$ かかる。
2017-05-13 追記
Heroku が公式に Let’s Encrypt に対応した。
Automated Certificate Management | Heroku Dev Center
heroku certs:auto:enable
のコマンド一発で対応で設定が完了するお手軽さ。
ということで以下の情報は、ほとんど使うところなくなったと思う。
概要
- Heroku で動かしている Rails アプリを SSL 対応する
- Heroku SSL (Beta) を Hobby Dyno で使う
- SSL 証明書は Let’s Encrypt で取得する
- SSL 証明書の自動更新はできていない
環境
- macOS 10.11.6
- Homebrew 0.9.9
基本的なこと
- Let’s Encrypt - Free SSL/TLS Certificates
- Getting Started - Let’s Encrypt - Free SSL/TLS Certificates
- Certbot
- Let’s Encrypt with a Rails app on Heroku // Collective Idea | Crafting web and mobile software based in Holland, Michigan
- Heroku SSL (Beta) | Heroku Dev Center
Certbot をインストールする
$ brew install certbot
証明書を取得する
方針
certbot
を manual モードで実行し、証明書を取得する。
manual モードでは、証明書取得時に certbot がドメインの所有者を認証するために、指定された URL にアクセスされたときに指定されたテキストを返すようにする必要がある。
まずは、その設定をしてから、certbot で証明書を取得していく。
Rails アプリからテキストを返す
static ページを作るときと同じように、ページ用のコントローラーを作る。
render
メソッドに Hash でテキストを渡せば、テキストを返せる。
render text: "your text here"
コントローラーを作って、アクションを実装して route する。いつもの Rails。
config/routes.rb
Rails.application.routes.draw do
get '/.well-known/acme-challenge/:id' => 'pages#certbot'
# and more
end
app/controller/pages_controller.rb
class PagesController < ApplicationController
def certbot
id = ENV['LETS_ENCRYPT_ID']
secret = ENV['LETS_ENCRYPT_SECRET']
if id.nil? || secret.nil?
render_404 and return
end
unless id == params[:id]
render_404 and return
end
render text: "#{id}.#{secret}"
end
private
def render_404
render file: Rails.root.join('public/404.html'), status: 404, layout: false, content_type: 'text/html'
end
end
※ id とか secret とかは、ここで適当に呼んでいるだけで、正式な名称ではない。
認証に必要な値は、環境変数で指定できるようにしておく。更新の度に Heroku に git push するのは嫌なため。
毎回 git push しても良いのであれば、public ディレクトリにファイルを置くというのもあり。
public/.well-known/acme-challenge/your-id-here-xxxxxx
というファイルに your-id-here-xxxxx.your-secret-here-yyyyy
を書き込んでおけば良いのでは。
証明書を取得する
manual モードで cerbot を実行して、証明書を取得しにいく。
certbot certonly --manual -d example.com
Permission Denied でこけるときは working directory を作ってオプションで指定すると良い。
# Permission でこけるとき
mkdir certbot
certbot certonly --manual -d example.com --logs-dir certbot --config-dir certbot --work-dir certbot
コマンドを実行すると、以下のところで一時停止する。
Make sure your web server displays the following content at
http://example.com/.well-known/acme-challenge/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx before continuing:
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
コマンドは一時停止させたまま、 Heroku に環境変数を設定する。
heroku config:set LETS_ENCRYPT_ID=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
heroku config:set LETS_ENCRYPT_SECRET=yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
設定が終わったら、実際に URL を叩いてみて、ちゃんとテキストが返ってくることを確認する。
確認が済んだら Enter でコマンドを resume する。成功すれば、証明書を保存したというメッセージが表示されるはず。
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at
/etc/letsencrypt/live/example.com/fullchain.pem. Your
cert will expire on xxxx-xx-xx. To obtain a new or tweaked version
of this certificate in the future, simply run certbot again. To
non-interactively renew *all* of your certificates, run "certbot
renew"
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
Heroku に証明書を設定する
Heroku で SSL と言えば、SSL Endpoint add-on ($20/month) が必要だったが、Heroku SSL (Beta) なら SSL 自体は無料で使えるようになった。 ただし、Paid Dyno が必要なので、最低でも Hobby ($7/month) はかかる。
Heroku SSL はまだ Beta なので、labs で有効にしてからインストールする。
heroku labs:enable http-sni -a your-app
heroku plugins:install heroku-certs
SSL 証明書と秘密鍵を設定する。
heroku _certs:add /etc/letsencrypt/live/example.com/cert.pem /etc/letsencrypt/live/example.com/privkey.pem
Resolving trust chain... done
Adding SSL certificate to ⬢ your-app... done
Certificate details:
Common Name(s): example.com
Expires At: xxxx-xx-xx xx:xx UTC
Issuer: /C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
Starts At: xxxx-xx-xx xx:xx UTC
Subject: /CN=example.com
SSL certificate is verified by a root authority.
=== Your certificate has been added successfully. Update your application's DNS settings as follows
Domain Record Type DNS Target
──────────────────────── ─────────── ──────────────────────────────────────
example.com CNAME example.com.herokudns.com
と言われるので、自分の使っている DNS に CNAME レコードを設定する。
最後に、証明書が設定できているかを確認する。
heroku _certs:info
これで、ひとまず完了
証明書の自動更新ができない問題
Let’s Encrypt の SSL 証明書は、自動更新を前提としているため、有効期限が短い。ただし、今回の構成では自動更新ができなかった。
manual モードは interactive な shell じゃないと実行できないし、manual モードで取得した証明書は non-interactive モードで renew
できない
まとめ・感想
- Heroku で動かしている Rails アプリを SSL 対応した
- Heroku SSL (Beta) を Hobby Dyno で使うことで、月 $7 で Rails アプリを SSL 対応できた
- SSL 証明書は Let’s Encrypt で取得した
- SSL 証明書の自動更新はできていない
自動更新絶対したくて、色々調べてみたけどできなかった。
今回のようにサーバーの外で certbot を動かすのではなくて、サーバー内で動かす方がメインっぽい。 Heroku 側で certbot 動かしてくれたり(standalone モードで実行して、ごにょごにょ)すると神 な気がするんですけど、どうなんでしょうか。