Herokuアプリでドメイン単位のリダイレクトをするには

以前の記事、Herokuアプリに独自ドメインを割り当てるの最後に書いたHerokuでのドメイン単位の転送に関する疑問点2つについて、解決したので備忘録。

疑問点2つ

Herokuアプリに独自ドメインを割り当てた後、2つの疑問点が浮上した。

  1. www.ruedap.com にアクセスしたら、ruedap.com に転送するようにしたい
    • www.ruedap.com でも同じ内容を表示するだけなら、前述のAレコードの設定で「www」も設定すれば良いんだろうけど、転送したいのでちょっと違う。こういう場合は独自ドメイン側じゃなく、リダイレクトをHerokuアプリ側でするのかな?
  2. 独自ドメイン設定後は、ruedap.heroku.com にアクセスしたら、ruedap.com に転送するようにしたい

これについて、@uzduraさんがアドバイスしてくれて「rack-rewriteというgemを使うと簡単に解決できるよ」と教えてもらった。さらに、そのrack-rewriteのreadmeを日本語訳した記事まで書いてくれているので、このgemを使うなら必見。

Rack::Rewrite の README を超訳してみました « blog.udzura.jp

で、rack-rewriteを使って試してみたところ、上記の疑問点2つともサクっと解決できた。

Rack::Rewriteを使う

今回は、自分がよく作るHeroku用Sinatraアプリの構造をベースにRack::Rewriteを使ってみる。既に稼動しているSinatraアプリを前提に、Gemfileconfig.ruの2ファイルを修正する。

Gemfile

Gemfileには、普通にrack-rewriteのgemを追加するだけ。

source :rubygems
gem 'sinatra'
gem 'slim'
gem 'sass'
gem 'rack-rewrite'  # これを追加

config.ru

config.ruには、前述のRack::Rewriteのreadmeの「CNAME の代わり」の項目を参考に、useメソッドを追加する。

require 'rubygems'
require 'bundler'
Bundler.require
# このメソッドを追加
if ENV['RACK_ENV'] == 'production'
  use Rack::Rewrite do
    r301 %r{.*}, 'http://ruedap.com$&', :if => Proc.new {|rack_env|
      rack_env['SERVER_NAME'] != 'ruedap.com'
    }
  end
end
require './app.rb'
run Sinatra::Application

useメソッド部分を文章で書くと、

  • アクセスしてきたドメインが「ruedap.com」じゃなかったら、「ruedap.com」に置き換えた上で、それ以降のパスを付け足す(リダイレクトする)

という感じかな? なんで引数がProcなのか、とか詳しいことはよくわからないけど動いた。あと、このリダイレクト処理が、例えばローカルでの動作チェック時のlocalhost:9292(rackup)やruedap.dev(Pow)などで起動した時もruedap.comにリダイレクトされたり、ステージング環境でも本番サイトにリダイレクトされてしまうのは問題がある。なのでRACK_ENVproductionの時だけ実行するようにifで囲う。これでHerokuにデプロイすると、以下の疑問点(2)の方が解決できる。

  • 独自ドメイン設定後は、ruedap.heroku.com にアクセスしたら、ruedap.com に転送するようにしたい

疑問点(1)の方は、www付きドメインwww.ruedap.comをHerokuへ向ける設定をしていないので、そもそもアクセスできない。ので、次の設定を加えることで解決する。

www付きドメインをwww無しドメインにリダイレクト

これは単に、www無しドメインruedap.comの時と同じように、www付きドメインwww.ruedap.comもHerokuのAレコード用IPアドレスを追加してHerokuへ向かうように設定してあげれば良いだけ。そうすればHerokuアプリ側では、さきほどRack::Rewriteを使って設定した条件の

  • アクセスしてきたドメインがruedap.comじゃなかったら、ruedap.comに置き換えた上で、それ以降のパスを付け足す(リダイレクトする)

が発動するので、www無しドメインにリダイレクトされる。ruedap.comはバリュードメインで取得したドメインなので、以下はバリュードメインでの設定手順。

バリュードメイン側の設定

バリュードメインの管理画面にログインしている状態で、以降の設定を行う。

  1. まず、取得済みドメイン一覧のページから、対象のドメイン(今回の場合はruedap.com)の「DNSレコードの変更/URL転送の変更」(緑色のDNSボタン)をクリックして、DNS設定画面を開く。
  2. DNS設定画面の設定フィールドで、www無しドメインの設定(上3行)の後ろに、www付きドメインの設定(下3行)を付け加えて保存する。
a @ 75.101.163.44
a @ 75.101.145.87
a @ 174.129.212.2
a www 75.101.163.44
a www 75.101.145.87
a www 174.129.212.2

これでwww.ruedap.com でもアクセスできるようになり、アクセスすればHeroku側でリダイレクトされるのでruedap.comになる。はず。というわけで疑問点(2)も解決。めでたしめでたし、となる予定が、まだめでたくなかった…。www.ruedap.comにアクセス出来るようになったら、エラー画面になってしまった。

エラー画面

Heroku側のドメイン設定も必要

Heroku側でのドメイン設定も必要だった。大前提としてwww.ruedap.comruedap.heroku.comで受けて、その後に先ほどのRack::Rewriteの処理が走るので、その大前提が抜け落ちてた!

$ heroku domains:add www.ruedap.com
Added www.ruedap.com as a custom domain name to ruedap.heroku.com

これでおk www.ruedap.com にアクセスしたら、ruedap.comに飛ばされた。というわけで疑問点(2)も解決。めでたしめでたし。教えてくれた@udzuraさんあざっす!

Sinatra上でも出来るけど

上記の疑問点2つは、Sinatraアプリで使える組み込み変数request.hostを使って、アクセスしてきたドメイン名を調べて同じようなことをやれば、おそらくSinatra上でも解決できそうだと思った。けど、

  1. 自分で全部書くよりは、既にライブラリ化されているコードに任せたほうがミスが少なそう
  2. Sinatraより一段低いレイヤーであるRack層で処理したほうが良い気がする
  3. Rack::Rewriteのreadmeには「rackupファイル(config.ru)にこうやって書くよ」と書かれているので、このライブラリを利用する人の多くは同じ場所に書きそう=config.ruを見ればrewriteルールが集まってると期待できそう

などの理由により、このライブラリを使ったほうが良いかなーと思ったけど、どうなんだろう? こういう時Railsなら、やり方が決まってて悩まなくても良いんだろうか。ということを、Railsを知らずにSinatraを使っていると良く思う。 Railsも使えるようにならねば…。


Rack::Rewrite の README を超訳してみました « blog.udzura.jp rack-rewrite README in japanese ― Gist